diff --git a/.editorconfig b/.editorconfig old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.vscode/settings.json b/.vscode/settings.json old mode 100644 new mode 100755 diff --git a/CLAUDE.md b/CLAUDE.md old mode 100644 new mode 100755 index 46ccce2..eb52472 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,44 +1,49 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +Guidance for Claude Code (claude.ai/code) when working in this repo. ## Project -MicCheck is an open source project written in asp.net, c#, typescript and VueJS that manages feature flags, their projects, and their environments. +MicCheck: open source. asp.net, c#, typescript, VueJS. Manages feature flags, projects, environments. ## Planned Structure -- `src/admin/` — administrative components in VueJS -- `src/api/` - api and restful endpoints in .NET +- `src/admin/` — VueJS admin components +- `src/api/` - .NET API + REST endpoints - `tests/` — test suite - `docs/` — documentation ## Best Practices -- Ensure all projects are using the latest LTS version of .NET as well as the latest supported nuget packages for that .NET version -- Ensure that langVersion is set to latest in all csproj files and nullable is enabled -- Code in all projects should be organized by feature or area instead of type. (e.g. a features namespace with all feature related code in it or in child namespaces of it) -- All new feature requests should include corresponding unit tests that cover as much of the logic as possible. -- Any file modified should be evaluated for potential test cases and missing coverage areas. +- Use latest LTS .NET + latest supported nuget packages for that version +- Set `langVersion` to latest in all csproj files; enable nullable +- Organize code by feature/area, not type (e.g. `features` namespace) +- New features need unit tests covering as much logic as possible +- Any modified file: evaluate for missing test coverage # Coding -- Use descriptive names for all classes and method created. Avoid generic names like Provider, Manager, Helper -- Coding should match formating and style rules in the .editorconfig file +- Descriptive names for all classes/methods. No generic names: Provider, Manager, Helper +- Match formatting/style from `.editorconfig` +- Wrap lines at 220 characters, leave single line if fewer +- Place interfaces that are implemented by a single class at the bottom of the class file. An interface with multiple implementations of an interface should be in a seperate file. +- Do not use tuples for return types. Prefer records or classes for multiple values +- Do not use `sealed` on classes- +- Use `record` for data objects, `class` for objects with behavior. Avoid mutable state where possible. ## Testing -- Write unit tests in a BDD style, testing as much code end-to-end as possible without without touching external resources like databases or file systems (e.g. WhenAUserDoesSomething_ThenAThingAppears) -- Mock any external dependencies using Moq. -- Do not name any mocked objects with the word Mock in them -- Do not include any Arrange / Act / Assert comments in the code - +- BDD-style unit tests, end-to-end as possible, no external resources (DB, filesystem). e.g. `WhenAUserDoesSomething_ThenAThingAppears` +- Mock external deps with Moq +- New features need unit tests covering as much logic as possible +- Any modified file: evaluate for missing test coverage- +- No "Mock" in mocked object names +- No Arrange/Act/Assert comments ## Claude -- Create all plans as .md file located in the `docs/` folder. Admin in `docs/admin/` and API in `docs/api/` -- Divide up large plans into discrete chucks of functionality so each can be built and committed independently. -- When generating a plan from a .md file in /docs/ save the plan in the same folder with the same filename minus the .md extention, but with a _plan.md at the end -- When implementing a plan from a .md file in /docs/ save the summary of the plan in the same folder with the same filename minus the .md extention, but with a _output.md at the end - +- Plans = `.md` files in `docs/`. Admin → `docs/admin/`, API → `docs/api/` +- Split large plans into discrete chunks — each buildable + committable independently +- Plan generated from `docs/.md` → save as `docs/_plan.md` +- Plan implemented from `docs/.md` → save summary as `docs/_output.md` ## Stack -The `.gitignore` is configured for a .NET/Visual Studio project (C#, NuGet, MSBuild). If this changes, update this file accordingly. +`.gitignore` configured for .NET/Visual Studio (C#, NuGet, MSBuild). Update if stack changes. \ No newline at end of file diff --git a/CLAUDE.original.md b/CLAUDE.original.md new file mode 100755 index 0000000..46ccce2 --- /dev/null +++ b/CLAUDE.original.md @@ -0,0 +1,44 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project + +MicCheck is an open source project written in asp.net, c#, typescript and VueJS that manages feature flags, their projects, and their environments. + +## Planned Structure + +- `src/admin/` — administrative components in VueJS +- `src/api/` - api and restful endpoints in .NET +- `tests/` — test suite +- `docs/` — documentation + +## Best Practices + +- Ensure all projects are using the latest LTS version of .NET as well as the latest supported nuget packages for that .NET version +- Ensure that langVersion is set to latest in all csproj files and nullable is enabled +- Code in all projects should be organized by feature or area instead of type. (e.g. a features namespace with all feature related code in it or in child namespaces of it) +- All new feature requests should include corresponding unit tests that cover as much of the logic as possible. +- Any file modified should be evaluated for potential test cases and missing coverage areas. + +# Coding +- Use descriptive names for all classes and method created. Avoid generic names like Provider, Manager, Helper +- Coding should match formating and style rules in the .editorconfig file + +## Testing +- Write unit tests in a BDD style, testing as much code end-to-end as possible without without touching external resources like databases or file systems (e.g. WhenAUserDoesSomething_ThenAThingAppears) +- Mock any external dependencies using Moq. +- Do not name any mocked objects with the word Mock in them +- Do not include any Arrange / Act / Assert comments in the code + + +## Claude +- Create all plans as .md file located in the `docs/` folder. Admin in `docs/admin/` and API in `docs/api/` +- Divide up large plans into discrete chucks of functionality so each can be built and committed independently. +- When generating a plan from a .md file in /docs/ save the plan in the same folder with the same filename minus the .md extention, but with a _plan.md at the end +- When implementing a plan from a .md file in /docs/ save the summary of the plan in the same folder with the same filename minus the .md extention, but with a _output.md at the end + + +## Stack + +The `.gitignore` is configured for a .NET/Visual Studio project (C#, NuGet, MSBuild). If this changes, update this file accordingly. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..01c2575 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 James Wampler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MicCheck.slnx b/MicCheck.slnx old mode 100644 new mode 100755 index 2443264..f24785e --- a/MicCheck.slnx +++ b/MicCheck.slnx @@ -1,8 +1,22 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml old mode 100644 new mode 100755 diff --git a/docs/admin/00-New-Website-output.md b/docs/admin/00-New-Website-output.md old mode 100644 new mode 100755 diff --git a/docs/admin/00-New-Website.md b/docs/admin/00-New-Website.md old mode 100644 new mode 100755 diff --git a/docs/admin/01-admin-site_plan.md b/docs/admin/01-admin-site_plan.md old mode 100644 new mode 100755 diff --git a/docs/api/00 - new-aspnet-project.md b/docs/api/00 - new-aspnet-project.md old mode 100644 new mode 100755 diff --git a/docs/api/00-output.md b/docs/api/00-output.md old mode 100644 new mode 100755 diff --git a/docs/api/01_project_setup.md b/docs/api/01_project_setup.md old mode 100644 new mode 100755 diff --git a/docs/api/01_project_setup_output.md b/docs/api/01_project_setup_output.md old mode 100644 new mode 100755 diff --git a/docs/api/02_core_domain_models.md b/docs/api/02_core_domain_models.md old mode 100644 new mode 100755 diff --git a/docs/api/02_core_domain_models_output.md b/docs/api/02_core_domain_models_output.md old mode 100644 new mode 100755 diff --git a/docs/api/03_database_and_repositories.md b/docs/api/03_database_and_repositories.md old mode 100644 new mode 100755 diff --git a/docs/api/03_database_and_repositories_output.md b/docs/api/03_database_and_repositories_output.md old mode 100644 new mode 100755 diff --git a/docs/api/04_authentication_and_authorization.md b/docs/api/04_authentication_and_authorization.md old mode 100644 new mode 100755 diff --git a/docs/api/04_authentication_and_authorization_output.md b/docs/api/04_authentication_and_authorization_output.md old mode 100644 new mode 100755 diff --git a/docs/api/05_flags_api.md b/docs/api/05_flags_api.md old mode 100644 new mode 100755 diff --git a/docs/api/05_flags_api_output.md b/docs/api/05_flags_api_output.md old mode 100644 new mode 100755 diff --git a/docs/api/06_admin_api.md b/docs/api/06_admin_api.md old mode 100644 new mode 100755 diff --git a/docs/api/06_admin_api_output.md b/docs/api/06_admin_api_output.md old mode 100644 new mode 100755 diff --git a/docs/api/07_audit_and_webhooks.md b/docs/api/07_audit_and_webhooks.md old mode 100644 new mode 100755 diff --git a/docs/api/07_audit_and_webhooks_output.md b/docs/api/07_audit_and_webhooks_output.md old mode 100644 new mode 100755 diff --git a/docs/api/08_testing_strategy.md b/docs/api/08_testing_strategy.md old mode 100644 new mode 100755 diff --git a/dotnet-install.sh b/dotnet-install.sh old mode 100644 new mode 100755 diff --git a/dotnet-tools.json b/dotnet-tools.json old mode 100644 new mode 100755 diff --git a/readme.md b/readme.md old mode 100644 new mode 100755 index e69de29..154ed50 --- a/readme.md +++ b/readme.md @@ -0,0 +1,42 @@ +# MicCheck + +Open source feature flag management platform. Manage projects, environments, feature flags, segments, and identities across your apps. + +Built with .NET (API) and Vue.js + Vuetify (admin UI). + +## Structure + +``` +src/ + api/MicCheck.Api/ .NET API — REST endpoints, organized by feature (Features, Projects, Environments, + Segments, Identities, Organizations, Webhooks, Audit, Users) + admin/ Vue.js + Vuetify admin SPA + MicCheck.AppHost/ .NET Aspire orchestration host for local dev + MicCheck.ServiceDefaults/ Shared .NET Aspire service defaults (telemetry, health checks) +tests/ + api/MicCheck.Api.Tests.Unit/ Unit tests + api/MicCheck.Api.Tests.Integration/ Integration tests +docs/ + admin/ Admin implementation plans/output docs + api/ API implementation plans/output docs +``` + +Code in the API is organized by feature area (e.g. `Features`, `Segments`, `Identities`) rather than by technical layer. + +## Running locally + +`docker-compose.yml` provides supporting services. `MicCheck.AppHost` (.NET Aspire) orchestrates the API and admin app for local development. + +```sh +./dev-build.sh +``` + +## Testing + +```sh +dotnet test +``` + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/src/MicCheck.AppHost/AppHost.cs b/src/MicCheck.AppHost/AppHost.cs new file mode 100755 index 0000000..e654c5d --- /dev/null +++ b/src/MicCheck.AppHost/AppHost.cs @@ -0,0 +1,14 @@ +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres").WithDataVolume("miccheck-pgdata").WithPgAdmin(); + +var miccheckDb = postgres.AddDatabase("miccheck"); + +var api = builder.AddProject("api").WithReference(miccheckDb).WaitFor(miccheckDb); + +builder.AddViteApp("admin", "../admin", "serve") + .WithReference(api) + .WaitFor(api) + .WithExternalHttpEndpoints(); + +builder.Build().Run(); diff --git a/src/MicCheck.AppHost/MicCheck.AppHost.csproj b/src/MicCheck.AppHost/MicCheck.AppHost.csproj new file mode 100755 index 0000000..6de3e45 --- /dev/null +++ b/src/MicCheck.AppHost/MicCheck.AppHost.csproj @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + Exe + net10.0 + enable + enable + latest + true + d10a4485-2ac0-4ba7-bda5-8eb63e417567 + + + diff --git a/src/MicCheck.AppHost/Properties/launchSettings.json b/src/MicCheck.AppHost/Properties/launchSettings.json new file mode 100755 index 0000000..3494766 --- /dev/null +++ b/src/MicCheck.AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17244;http://localhost:15050", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21229", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22051" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15050", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19033", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20209" + } + } + } +} diff --git a/src/MicCheck.AppHost/appsettings.Development.json b/src/MicCheck.AppHost/appsettings.Development.json new file mode 100755 index 0000000..57715f5 --- /dev/null +++ b/src/MicCheck.AppHost/appsettings.Development.json @@ -0,0 +1,16 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "Dashboard": { + "Frontend": { + "AuthMode": "Unsecured" + }, + "Otlp": { + "AuthMode": "Unsecured" + } + } +} diff --git a/src/MicCheck.AppHost/appsettings.json b/src/MicCheck.AppHost/appsettings.json new file mode 100755 index 0000000..2185f95 --- /dev/null +++ b/src/MicCheck.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/src/MicCheck.AppHost/aspire.config.json b/src/MicCheck.AppHost/aspire.config.json new file mode 100755 index 0000000..c083953 --- /dev/null +++ b/src/MicCheck.AppHost/aspire.config.json @@ -0,0 +1,5 @@ +{ + "appHost": { + "path": "MicCheck.AppHost.csproj" + } +} diff --git a/src/MicCheck.ServiceDefaults/Extensions.cs b/src/MicCheck.ServiceDefaults/Extensions.cs new file mode 100755 index 0000000..97642a1 --- /dev/null +++ b/src/MicCheck.ServiceDefaults/Extensions.cs @@ -0,0 +1,127 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting; + +// Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/aspire/service-defaults +public static class Extensions +{ + private const string HealthEndpointPath = "/health"; + private const string AlivenessEndpointPath = "/alive"; + + public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + + return builder; + } + + public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation(tracing => + // Exclude health check requests from tracing + tracing.Filter = context => + !context.Request.Path.StartsWithSegments(HealthEndpointPath) + && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) + ) + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks(HealthEndpointPath); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } +} diff --git a/src/MicCheck.ServiceDefaults/MicCheck.ServiceDefaults.csproj b/src/MicCheck.ServiceDefaults/MicCheck.ServiceDefaults.csproj new file mode 100755 index 0000000..bec9d25 --- /dev/null +++ b/src/MicCheck.ServiceDefaults/MicCheck.ServiceDefaults.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + latest + true + true + + + + + + + + + + + + + + + diff --git a/src/admin/.dockerignore b/src/admin/.dockerignore old mode 100644 new mode 100755 diff --git a/src/admin/Admin.esproj b/src/admin/Admin.esproj new file mode 100755 index 0000000..3899bea --- /dev/null +++ b/src/admin/Admin.esproj @@ -0,0 +1,11 @@ + + + npm run serve + .\ + Jest + + false + + $(MSBuildProjectDirectory)\dist + + \ No newline at end of file diff --git a/src/admin/Dockerfile b/src/admin/Dockerfile old mode 100644 new mode 100755 diff --git a/src/admin/babel.config.js b/src/admin/babel.config.js old mode 100644 new mode 100755 diff --git a/src/admin/index.html b/src/admin/index.html old mode 100644 new mode 100755 diff --git a/src/admin/jest.config.js b/src/admin/jest.config.js old mode 100644 new mode 100755 index d7fe9b9..1e2185f --- a/src/admin/jest.config.js +++ b/src/admin/jest.config.js @@ -16,12 +16,19 @@ module.exports = { '^.+\\.[jt]sx?$': 'babel-jest', }, transformIgnorePatterns: [ - '/node_modules/(?!(vuetify)/)', + '/node_modules/(?!(vuetify|@vueuse|@iconify)/)', ], moduleNameMapper: { '\\.(css|scss|sass)$': '/tests/__mocks__/styleMock.js', '\\.(svg|png|jpg|jpeg|gif|webp|woff2?)$': '/tests/__mocks__/fileMock.js', '^@/(.*)$': '/src/$1', + '^@core/(.*)$': '/src/@core/$1', + '^@core$': '/src/@core', + '^@layouts/(.*)$': '/src/@layouts/$1', + '^@layouts$': '/src/@layouts', + '^@images/(.*)$': '/src/assets/images/$1', + '^@styles/(.*)$': '/src/assets/styles/$1', + '^@configured-variables$': '/tests/__mocks__/styleMock.js', }, globals: { 'vue-jest': { diff --git a/src/admin/nginx.conf b/src/admin/nginx.conf old mode 100644 new mode 100755 diff --git a/src/admin/package-lock.json b/src/admin/package-lock.json old mode 100644 new mode 100755 index 1971b66..63d9467 --- a/src/admin/package-lock.json +++ b/src/admin/package-lock.json @@ -1,10388 +1,11534 @@ -{ - "name": "mic-check-admin", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "mic-check-admin", - "version": "1.0.0", - "dependencies": { - "@mdi/js": "^7.4.47", - "axios": "^1.15.0", - "pinia": "^3.0.4", - "vue": "^3.4.0", - "vue-router": "^4.3.0", - "vuetify": "^3.6.0" - }, - "devDependencies": { - "@babel/core": "^7.24.0", - "@babel/preset-env": "^7.24.0", - "@babel/preset-typescript": "^7.24.0", - "@types/jest": "^29.5.12", - "@types/node": "^20.12.0", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/test-utils": "^2.4.6", - "@vue/vue3-jest": "^29.2.6", - "babel-jest": "^29.7.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "sass": "^1.77.2", - "ts-jest": "^29.1.4", - "typescript": "^5.4.5", - "vite": "^8.0.8", - "vite-plugin-vuetify": "^2.1.3" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "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/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.6", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", - "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", - "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", - "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", - "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", - "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", - "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", - "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", - "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", - "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", - "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", - "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/template": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", - "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", - "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", - "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", - "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", - "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", - "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", - "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", - "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", - "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", - "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", - "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", - "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", - "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", - "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", - "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", - "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", - "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", - "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", - "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", - "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.28.6", - "@babel/plugin-syntax-import-attributes": "^7.28.6", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.29.0", - "@babel/plugin-transform-async-to-generator": "^7.28.6", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.6", - "@babel/plugin-transform-class-properties": "^7.28.6", - "@babel/plugin-transform-class-static-block": "^7.28.6", - "@babel/plugin-transform-classes": "^7.28.6", - "@babel/plugin-transform-computed-properties": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.28.6", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.6", - "@babel/plugin-transform-exponentiation-operator": "^7.28.6", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.28.6", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", - "@babel/plugin-transform-numeric-separator": "^7.28.6", - "@babel/plugin-transform-object-rest-spread": "^7.28.6", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.28.6", - "@babel/plugin-transform-optional-chaining": "^7.28.6", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.28.6", - "@babel/plugin-transform-private-property-in-object": "^7.28.6", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.29.0", - "@babel/plugin-transform-regexp-modifiers": "^7.28.6", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.28.6", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.28.6", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.15", - "babel-plugin-polyfill-corejs3": "^0.14.0", - "babel-plugin-polyfill-regenerator": "^0.6.6", - "core-js-compat": "^3.48.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", - "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/console/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, - "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/@jest/console/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/console/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 - }, - "node_modules/@jest/console/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/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, - "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/@jest/core/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/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 - }, - "node_modules/@jest/core/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/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, - "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/@jest/reporters/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/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 - }, - "node_modules/@jest/reporters/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/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, - "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/@jest/transform/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/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 - }, - "node_modules/@jest/transform/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/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, - "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/@jest/types/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/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 - }, - "node_modules/@jest/types/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "devOptional": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "devOptional": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "devOptional": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mdi/js": { - "version": "7.4.47", - "resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz", - "integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==" - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@one-ini/wasm": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", - "dev": true - }, - "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", - "devOptional": true, - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", - "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.6", - "@parcel/watcher-darwin-arm64": "2.5.6", - "@parcel/watcher-darwin-x64": "2.5.6", - "@parcel/watcher-freebsd-x64": "2.5.6", - "@parcel/watcher-linux-arm-glibc": "2.5.6", - "@parcel/watcher-linux-arm-musl": "2.5.6", - "@parcel/watcher-linux-arm64-glibc": "2.5.6", - "@parcel/watcher-linux-arm64-musl": "2.5.6", - "@parcel/watcher-linux-x64-glibc": "2.5.6", - "@parcel/watcher-linux-x64-musl": "2.5.6", - "@parcel/watcher-win32-arm64": "2.5.6", - "@parcel/watcher-win32-ia32": "2.5.6", - "@parcel/watcher-win32-x64": "2.5.6" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", - "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", - "cpu": [ - "arm64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", - "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", - "cpu": [ - "arm64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", - "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", - "cpu": [ - "x64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", - "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", - "cpu": [ - "x64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", - "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", - "cpu": [ - "arm" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", - "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", - "cpu": [ - "arm" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", - "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", - "cpu": [ - "arm64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", - "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", - "cpu": [ - "arm64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", - "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", - "cpu": [ - "x64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", - "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", - "cpu": [ - "x64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", - "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", - "cpu": [ - "arm64" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", - "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", - "cpu": [ - "ia32" - ], - "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.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", - "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "optional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", - "cpu": [ - "wasm32" - ], - "optional": true, - "dependencies": { - "@emnapi/core": "1.9.2", - "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz", - "integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==", - "dev": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.10", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", - "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "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==", - "optional": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "optional": true, - "peer": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "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==", - "optional": true, - "peer": true - }, - "node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", - "devOptional": true, - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true - }, - "node_modules/@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true - }, - "node_modules/@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", - "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@vitejs/plugin-vue": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.6.tgz", - "integrity": "sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==", - "dev": true, - "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.13" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", - "vue": "^3.2.25" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", - "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", - "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.31", - "entities": "^7.0.1", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", - "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", - "dependencies": { - "@vue/compiler-core": "3.5.31", - "@vue/shared": "3.5.31" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.31.tgz", - "integrity": "sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==", - "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.31", - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.8", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.31.tgz", - "integrity": "sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==", - "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/shared": "3.5.31" - } - }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" - }, - "node_modules/@vue/devtools-kit": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", - "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", - "dependencies": { - "@vue/devtools-shared": "^7.7.9", - "birpc": "^2.3.0", - "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^1.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.2" - } - }, - "node_modules/@vue/devtools-shared": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", - "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", - "dependencies": { - "rfdc": "^1.4.1" - } - }, - "node_modules/@vue/reactivity": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.31.tgz", - "integrity": "sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==", - "dependencies": { - "@vue/shared": "3.5.31" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.31.tgz", - "integrity": "sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==", - "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/shared": "3.5.31" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.31.tgz", - "integrity": "sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==", - "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/runtime-core": "3.5.31", - "@vue/shared": "3.5.31", - "csstype": "^3.2.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.31.tgz", - "integrity": "sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==", - "dependencies": { - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31" - }, - "peerDependencies": { - "vue": "3.5.31" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", - "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==" - }, - "node_modules/@vue/test-utils": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", - "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", - "dev": true, - "dependencies": { - "js-beautify": "^1.14.9", - "vue-component-type-helpers": "^2.0.0" - } - }, - "node_modules/@vue/vue3-jest": { - "version": "29.2.6", - "resolved": "https://registry.npmjs.org/@vue/vue3-jest/-/vue3-jest-29.2.6.tgz", - "integrity": "sha512-Hy4i2BsV5fUmER5LplYiAeRkLTDCSB3ZbnAeEawXtjto/ILaOnamBAoAvEqARgPpR6NRtiYjSgGKmllMtnFd9g==", - "dev": true, - "dependencies": { - "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "chalk": "^2.1.0", - "convert-source-map": "^1.6.0", - "css-tree": "^2.0.1", - "source-map": "0.5.6", - "tsconfig": "^7.0.0" - }, - "engines": { - "node": ">10" - }, - "peerDependencies": { - "@babel/core": "7.x", - "babel-jest": "29.x", - "jest": "29.x", - "typescript": ">= 4.3", - "vue": "^3.0.0-0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/vue3-jest/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@vuetify/loader-shared": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-2.1.2.tgz", - "integrity": "sha512-X+1jBLmXHkpQEnC0vyOb4rtX2QSkBiFhaFXz8yhQqN2A4vQ6k2nChxN4Ol7VAY5KoqMdFoRMnmNdp/1qYXDQig==", - "devOptional": true, - "dependencies": { - "upath": "^2.0.1" - }, - "peerDependencies": { - "vue": "^3.0.0", - "vuetify": ">=3" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "optional": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "optional": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "optional": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "optional": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "optional": true, - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "optional": true, - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "optional": true, - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "optional": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "optional": true, - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "optional": true, - "peer": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "devOptional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, - "dependencies": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" - } - }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.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==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/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, - "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/babel-jest/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/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 - }, - "node_modules/babel-jest/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", - "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", - "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8", - "core-js-compat": "^3.48.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", - "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.11.tgz", - "integrity": "sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==", - "devOptional": true, - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "optional": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/birpc": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", - "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "devOptional": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "devOptional": true - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", - "optional": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "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, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001781", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", - "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", - "devOptional": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "devOptional": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "optional": true, - "peer": true - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", - "dependencies": { - "is-what": "^5.2.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", - "dev": true, - "dependencies": { - "browserslist": "^4.28.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-jest/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/create-jest/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, - "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/create-jest/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/create-jest/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 - }, - "node_modules/create-jest/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/create-jest/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "devOptional": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decache": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/decache/-/decache-4.6.2.tgz", - "integrity": "sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==", - "optional": true, - "peer": true, - "dependencies": { - "callsite": "^1.0.0" - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true - }, - "node_modules/dedent": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", - "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", - "dev": true, - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/editorconfig": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", - "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", - "dev": true, - "dependencies": { - "@one-ini/wasm": "0.1.1", - "commander": "^10.0.0", - "minimatch": "^9.0.1", - "semver": "^7.5.3" - }, - "bin": { - "editorconfig": "bin/editorconfig" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/editorconfig/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.325", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.325.tgz", - "integrity": "sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==", - "devOptional": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", - "optional": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "optional": true, - "peer": true - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "devOptional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "optional": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "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==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "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==", - "optional": true, - "peer": true, - "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==", - "devOptional": true, - "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==" - }, - "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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.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==", - "optional": true, - "peer": true - }, - "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==", - "devOptional": true - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "optional": true, - "peer": true - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "optional": true, - "peer": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/file-loader/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "optional": true, - "peer": true, - "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/file-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "optional": true, - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/file-loader/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==", - "optional": true, - "peer": true - }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-5.0.0.tgz", - "integrity": "sha512-OuWNfjfP05JcpAP3JPgAKUhWefjMRfI5iAoSsvE24ANYWJaepAtlSgWECSVEuRgSXpyNEc9DJwG/TZpgcOqyig==", - "optional": true, - "peer": true, - "dependencies": { - "common-path-prefix": "^3.0.0", - "pkg-dir": "^7.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "optional": true, - "peer": true, - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "optional": true, - "peer": true, - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "optional": true, - "peer": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "optional": true, - "peer": true, - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "optional": true, - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", - "optional": true, - "peer": true, - "dependencies": { - "find-up": "^6.3.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "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, - "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==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "optional": true, - "peer": true - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "devOptional": true - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hookable": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "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==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/immutable": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", - "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", - "devOptional": true - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "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==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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==", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/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, - "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/jest-circus/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/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 - }, - "node_modules/jest-circus/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/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, - "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/jest-cli/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/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 - }, - "node_modules/jest-cli/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/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, - "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/jest-config/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/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 - }, - "node_modules/jest-config/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/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, - "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/jest-diff/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/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 - }, - "node_modules/jest-diff/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/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, - "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/jest-each/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/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 - }, - "node_modules/jest-each/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", - "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0", - "jsdom": "^20.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/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, - "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/jest-matcher-utils/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/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 - }, - "node_modules/jest-matcher-utils/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/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, - "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/jest-message-util/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/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 - }, - "node_modules/jest-message-util/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/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, - "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/jest-resolve/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/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 - }, - "node_modules/jest-resolve/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/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, - "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/jest-runner/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/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 - }, - "node_modules/jest-runner/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/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, - "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/jest-runtime/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/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 - }, - "node_modules/jest-runtime/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/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, - "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/jest-snapshot/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/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 - }, - "node_modules/jest-snapshot/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/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, - "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/jest-util/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/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 - }, - "node_modules/jest-util/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/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, - "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/jest-validate/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/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 - }, - "node_modules/jest-validate/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/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, - "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/jest-watcher/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/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 - }, - "node_modules/jest-watcher/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-beautify": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", - "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", - "dev": true, - "dependencies": { - "config-chain": "^1.1.13", - "editorconfig": "^1.0.4", - "glob": "^10.4.2", - "js-cookie": "^3.0.5", - "nopt": "^7.2.1" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/js-beautify/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "acorn": "^8.8.1", - "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.2", - "parse5": "^7.1.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "devOptional": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "optional": true, - "peer": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "devOptional": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "devOptional": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "optional": true, - "peer": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "devOptional": true - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "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==", - "devOptional": true - }, - "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" - } - ], - "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 - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "devOptional": true - }, - "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==", - "optional": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", - "devOptional": true - }, - "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "dev": true, - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/null-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", - "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", - "optional": true, - "peer": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/null-loader/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "optional": true, - "peer": true, - "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/null-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "optional": true, - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/null-loader/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==", - "optional": true, - "peer": true - }, - "node_modules/null-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/perfect-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pinia": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", - "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", - "dependencies": { - "@vue/devtools-api": "^7.7.7" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "typescript": ">=4.5.0", - "vue": "^3.5.11" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/pinia/node_modules/@vue/devtools-api": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", - "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", - "dependencies": { - "@vue/devtools-kit": "^7.7.9" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "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" - } - ], - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", - "dev": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/lupomontero" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "devOptional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "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, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "dependencies": { - "is-core-module": "^2.16.1", - "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-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" - }, - "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", - "devOptional": true, - "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" - } - }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", - "devOptional": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sass": { - "version": "1.98.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.98.0.tgz", - "integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", - "devOptional": true, - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.1.5", - "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/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "optional": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "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, - "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, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", - "dev": true, - "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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superjson": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", - "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", - "dependencies": { - "copy-anything": "^4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/tapable": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", - "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", - "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/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==", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "optional": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true, - "peer": true - }, - "node_modules/terser/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==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "optional": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "devOptional": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "devOptional": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "devOptional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", - "dev": true, - "dependencies": { - "bs-logger": "^0.2.6", - "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.3", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0 || ^30.0.0", - "@jest/types": "^29.0.0 || ^30.0.0", - "babel-jest": "^29.0.0 || ^30.0.0", - "jest": "^29.0.0 || ^30.0.0", - "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jest-util": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", - "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", - "dev": true, - "dependencies": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "node_modules/tsconfig/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "optional": true - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "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==", - "devOptional": true - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/upath": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", - "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", - "devOptional": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "devOptional": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "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==", - "optional": true, - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", - "devOptional": true, - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "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/vite-plugin-vuetify": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.3.tgz", - "integrity": "sha512-Q4SC/4TqbNvaZIFb9YsfBqkGlYHbJJJ6uU3CnRBZqLUF3s5eCMVZAaV4GkTbehIH/bhSj42lMXztOwc71u6rVw==", - "devOptional": true, - "dependencies": { - "@vuetify/loader-shared": "^2.1.2", - "debug": "^4.3.3", - "upath": "^2.0.1" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": ">=5", - "vue": "^3.0.0", - "vuetify": ">=3" - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "devOptional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vue": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", - "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", - "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-sfc": "3.5.31", - "@vue/runtime-dom": "3.5.31", - "@vue/server-renderer": "3.5.31", - "@vue/shared": "3.5.31" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vue-component-type-helpers": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", - "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", - "dev": true - }, - "node_modules/vue-router": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", - "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", - "dependencies": { - "@vue/devtools-api": "^6.6.4" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.5.0" - } - }, - "node_modules/vuetify": { - "version": "3.12.4", - "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.12.4.tgz", - "integrity": "sha512-9pyvSdL4vGEioOSJKjoyRxyPc2HYYINWkwxE4ku8PuGGRhCoEchXL57EL1JabIy+D8lUsx+co/G+tUaksvpXrw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/johnleider" - }, - "peerDependencies": { - "typescript": ">=4.7", - "vite-plugin-vuetify": ">=2.1.0", - "vue": "^3.5.0", - "webpack-plugin-vuetify": ">=3.1.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "vite-plugin-vuetify": { - "optional": true - }, - "webpack-plugin-vuetify": { - "optional": true - } - } - }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", - "optional": true, - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/webpack": { - "version": "5.105.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", - "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", - "optional": true, - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.20.0", - "es-module-lexer": "^2.0.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.17", - "watchpack": "^2.5.1", - "webpack-sources": "^3.3.4" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-plugin-vuetify": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/webpack-plugin-vuetify/-/webpack-plugin-vuetify-3.1.3.tgz", - "integrity": "sha512-0o3H+UEgeZh47vjgLeHbbFl+oZUpnRadRUyk6xCMXSZQR1Jh0ZnfzYC79+fO83OWlMpv2AqHbJkEXwDKnCafYA==", - "optional": true, - "peer": true, - "dependencies": { - "@vuetify/loader-shared": "^2.1.2", - "decache": "^4.6.0", - "file-loader": "^6.2.0", - "find-cache-dir": "^5.0.0", - "loader-utils": "^2.0.0", - "mkdirp": "^1.0.4", - "null-loader": "^4.0.1", - "upath": "^2.0.1" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@vue/compiler-sfc": "^3.2.6", - "vue": "^3.2.6", - "vuetify": ">=3", - "webpack": "^5.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/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 - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/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 - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} +{ + "name": "mic-check-admin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mic-check-admin", + "version": "1.0.0", + "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@iconify-json/bxl": "^1.2.0", + "@iconify-json/ri": "^1.2.0", + "@iconify/vue": "^4.1.0", + "@vueuse/core": "^11.0.0", + "apexcharts": "^5.15.0", + "axios": "^1.15.0", + "pinia": "^3.0.4", + "vue": "^3.4.0", + "vue-router": "^4.3.0", + "vue3-apexcharts": "^1.11.1", + "vue3-perfect-scrollbar": "^2.0.0", + "vuetify": "^3.7.5" + }, + "devDependencies": { + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", + "@babel/preset-typescript": "^7.24.0", + "@types/jest": "^29.5.12", + "@types/node": "^20.12.0", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/test-utils": "^2.4.6", + "@vue/vue3-jest": "^29.2.6", + "babel-jest": "^29.7.0", + "eslint": "^10.4.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "sass": "^1.77.2", + "sass-embedded": "^1.77.0", + "ts-jest": "^29.1.4", + "typescript": "^5.4.5", + "vite": "^8.0.8", + "vite-plugin-vuetify": "^2.1.3", + "vite-svg-loader": "^5.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "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/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "devOptional": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "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.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@fontsource-variable/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify-json/bxl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@iconify-json/bxl/-/bxl-1.2.4.tgz", + "integrity": "sha512-R6gVQSxB1+XeVClK7KdACnk1SfP8xiAu6LHuKZmp6Ro5zwMQbpe9vFBv30F6eHMDL8lZ7eXuac5SRJ9C8DKehQ==", + "license": "MIT", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify-json/ri": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@iconify-json/ri/-/ri-1.2.10.tgz", + "integrity": "sha512-WWMhoncVVM+Xmu9T5fgu2lhYRrKTEWhKk3Com0KiM111EeEsRLiASjpsFKnC/SrB6covhUp95r2mH8tGxhgd5Q==", + "license": "Apache-2.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/vue": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@iconify/vue/-/vue-4.3.0.tgz", + "integrity": "sha512-Xq0h6zMrHBbrW8jXJ9fISi+x8oDQllg5hTDkDuxnWiskJ63rpJu9CvJshj8VniHVTbsxCg9fVoPAaNp3RQI5OQ==", + "license": "MIT", + "dependencies": { + "@iconify/types": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/cyberalien" + }, + "peerDependencies": { + "vue": ">=3" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/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/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "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.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "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/node": { + "version": "20.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", + "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", + "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.35", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", + "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.35", + "@vue/shared": "3.5.35" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", + "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.35", + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", + "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.35", + "@vue/shared": "3.5.35" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", + "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.35" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", + "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.35", + "@vue/shared": "3.5.35" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", + "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.35", + "@vue/runtime-core": "3.5.35", + "@vue/shared": "3.5.35", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", + "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35" + }, + "peerDependencies": { + "vue": "3.5.35" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", + "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "license": "MIT" + }, + "node_modules/@vue/test-utils": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.10.tgz", + "integrity": "sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-beautify": "^1.14.9", + "vue-component-type-helpers": "^3.0.0" + }, + "peerDependencies": { + "@vue/compiler-dom": "3.x", + "@vue/server-renderer": "3.x", + "vue": "3.x" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } + } + }, + "node_modules/@vue/vue3-jest": { + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/@vue/vue3-jest/-/vue3-jest-29.2.6.tgz", + "integrity": "sha512-Hy4i2BsV5fUmER5LplYiAeRkLTDCSB3ZbnAeEawXtjto/ILaOnamBAoAvEqARgPpR6NRtiYjSgGKmllMtnFd9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "chalk": "^2.1.0", + "convert-source-map": "^1.6.0", + "css-tree": "^2.0.1", + "source-map": "0.5.6", + "tsconfig": "^7.0.0" + }, + "engines": { + "node": ">10" + }, + "peerDependencies": { + "@babel/core": "7.x", + "babel-jest": "29.x", + "jest": "29.x", + "typescript": ">= 4.3", + "vue": "^3.0.0-0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/vue3-jest/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vuetify/loader-shared": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-2.1.2.tgz", + "integrity": "sha512-X+1jBLmXHkpQEnC0vyOb4rtX2QSkBiFhaFXz8yhQqN2A4vQ6k2nChxN4Ol7VAY5KoqMdFoRMnmNdp/1qYXDQig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "upath": "^2.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0", + "vuetify": ">=3" + } + }, + "node_modules/@vueuse/core": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.3.0.tgz", + "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "11.3.0", + "@vueuse/shared": "11.3.0", + "vue-demi": ">=0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.3.0.tgz", + "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", + "license": "MIT", + "dependencies": { + "vue-demi": ">=0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "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/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.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.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "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-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/apexcharts": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.15.0.tgz", + "integrity": "sha512-ATswoiZi8wynKcwqf0eyE0Is5mBQoDpxZN3PlSVy41OrD+9GMBp2kZQRjyGK+5/j0GFjHkuAd7GKOrt5VMoPrw==" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/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/babel-jest/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/babel-jest/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/babel-jest/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/babel-jest/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/babel-jest/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/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/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/create-jest/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/create-jest/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/create-jest/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/create-jest/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/create-jest/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/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/editorconfig": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "^9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.366", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.366.tgz", + "integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz", + "integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.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", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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==", + "dev": true, + "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/eslint/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "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==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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==", + "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/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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-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/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "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/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "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/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "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.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "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==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/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/istanbul-lib-report/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/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/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/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/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/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/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/jest-validate/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/jest-validate/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/jest-validate/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/jest-validate/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/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-cookie": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.8.tgz", + "integrity": "sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-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-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "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==", + "dev": true, + "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": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "devOptional": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "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.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "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/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "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-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz", + "integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==", + "license": "MIT" + }, + "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": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^7.7.7" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.5.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "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.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "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/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "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-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-embedded": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.100.0.tgz", + "integrity": "sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.5.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.1.5", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-all-unknown": "1.100.0", + "sass-embedded-android-arm": "1.100.0", + "sass-embedded-android-arm64": "1.100.0", + "sass-embedded-android-riscv64": "1.100.0", + "sass-embedded-android-x64": "1.100.0", + "sass-embedded-darwin-arm64": "1.100.0", + "sass-embedded-darwin-x64": "1.100.0", + "sass-embedded-linux-arm": "1.100.0", + "sass-embedded-linux-arm64": "1.100.0", + "sass-embedded-linux-musl-arm": "1.100.0", + "sass-embedded-linux-musl-arm64": "1.100.0", + "sass-embedded-linux-musl-riscv64": "1.100.0", + "sass-embedded-linux-musl-x64": "1.100.0", + "sass-embedded-linux-riscv64": "1.100.0", + "sass-embedded-linux-x64": "1.100.0", + "sass-embedded-unknown-all": "1.100.0", + "sass-embedded-win32-arm64": "1.100.0", + "sass-embedded-win32-x64": "1.100.0" + } + }, + "node_modules/sass-embedded-all-unknown": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.100.0.tgz", + "integrity": "sha512-auFtXY/kwYILmSVjtBDwyj0axcLbYYiffOKWoaXHnI5bsYwiRbBh3EneR1rpbX2ZIZCrwX93i5pxKLTZF/662Q==", + "cpu": [ + "!arm", + "!arm64", + "!riscv64", + "!x64" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "sass": "1.100.0" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.100.0.tgz", + "integrity": "sha512-70f3HgX2pFNmzpGQ86n5e6QfWn2fP4QUQGfFQK0P1XH73ZLIzLo2YqygrGKGKeeqtc5eU2Wl1/xQzhzuKnO4kw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.100.0.tgz", + "integrity": "sha512-W+Ru9JwTnfU0UX3jSZcbqFdtKFMcYdfFwytc57h2DgnqCOIiAqI2E06mABZBZC+r3LwXCBuS5GbXAGeVgvVDkA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.100.0.tgz", + "integrity": "sha512-icU3o0V/uCSytSpf+tX5Lf51BvyQEbLzDUJfUi9etSauYBGHpPKkdtdZH0si4v98phq11Kl8rSV1SggksxF1Hg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.100.0.tgz", + "integrity": "sha512-mevF9VQk6gEYByy8+jusaHGmd7Usb2ytX/DsEOd0JtOGCtcf1kh575xJ6OUBDIcJ15uLnbau/0iy1eP6WVBvWA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.100.0.tgz", + "integrity": "sha512-1PVlYi61POo93IT/FfrG1mc1tAHxeSTyUALF2aOFmXGWjVXr3bQzEQiBGCOvQbj/ix+5hNyXFXcEMEyKvtUJJA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.100.0.tgz", + "integrity": "sha512-x97o3JnGyImZNCIVs9wQHJUE5QCvmVIKaH1cwrz/5dK7OT1FpeNiW+u9TUomP9hG6Ekjd8EL8NBHpxTfIhdjmg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.100.0.tgz", + "integrity": "sha512-9Ul7O1eKrc5YlhwWjkp8tZPSe3UEwSZ1uwUZOQom1HL0pRlBA6F/IlGZYFTLwnHMIP1fc77MMNaBRfc05mKMpw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.100.0.tgz", + "integrity": "sha512-Dwjmj8Z6VRy7rAi53JAdEwIyUjpfl7PhpSc2/LpQPQx+aO5Dp7Spaipkax0ufJl1SoDUdchCsM4y/88YaluorQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.100.0.tgz", + "integrity": "sha512-sl0JgbGloPyJg66XXx5UDSDScZ0oU85DpMQU4JU/sCUCFj1Z8zZ69SJWKTCNE4/jwnce7WI2zPCV5AG+RHOZJw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.100.0.tgz", + "integrity": "sha512-XpACJB2KjSLjf2e9uuvGVdOURsoNrFqgRiihhXyUHK9W0t3LIHb7z5MA/7XGPIT9bWSOO2zyw+rH/FHtDV/Yrg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.100.0.tgz", + "integrity": "sha512-ShvI0Kx04mwoCARwZ0UjiT97isQvzO80tAt91zmFyHLN9kelc/IrQi940farSm2xQVPCKdeVyeG0ekBsokSpYQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.100.0.tgz", + "integrity": "sha512-TDBCRWNuS4RDLQXvRc1gjZlWiWTWaWGp0Bwu/IKwJxov81lsvrCs3TihTyNXtW7V5aoN4Ky3r0QOkNb3mwmBnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.100.0.tgz", + "integrity": "sha512-j4ENJGOheO+fm3j/yorLxCjBP6/XskrZx7dTLlT+lXYwN/qqCqoA/gsNLI0McS3DFM6GBwPiffzWsdWS8t6sEQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.100.0.tgz", + "integrity": "sha512-0vUSN8j0WGtCJIOPh//EmUvYGHW0QOe5iul8qyhPk50MAcw49MA0r34AhftjDdx94ILPF6vApFs0gwHPQRlpVA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-unknown-all": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.100.0.tgz", + "integrity": "sha512-c+naBgWId4MIpToXcI0DgqetjdAkwTTAxFAuOaBz7HUXLdyG1oZRrEvSsbe41nEdQOKH0vgofVFCeSQgoXOG9A==", + "license": "MIT", + "optional": true, + "os": [ + "!android", + "!darwin", + "!linux", + "!win32" + ], + "dependencies": { + "sass": "1.100.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.100.0.tgz", + "integrity": "sha512-iE+yxj+hUXwwbqpHkXxgAWTzeRfcWxJ7SSTQEPMk48lwq3oCrWLlz5sQuWHbuTK/i0GKQfROdP+hOmPi89yjUg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.100.0.tgz", + "integrity": "sha512-qI4F8MI7/KYoy9NdjJfhSspG42WPkADSNDvwEV7qWvCSFC83koJssRsKO2/PfY+niZz6BG65Ic/D+A11h959hw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/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==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/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/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", + "dev": true, + "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/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", + "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-jest": { + "version": "29.4.11", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", + "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.0", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "devOptional": true, + "license": "0BSD" + }, + "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/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/vite-plugin-vuetify": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.3.tgz", + "integrity": "sha512-Q4SC/4TqbNvaZIFb9YsfBqkGlYHbJJJ6uU3CnRBZqLUF3s5eCMVZAaV4GkTbehIH/bhSj42lMXztOwc71u6rVw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@vuetify/loader-shared": "^2.1.2", + "debug": "^4.3.3", + "upath": "^2.0.1" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": ">=5", + "vue": "^3.0.0", + "vuetify": ">=3" + } + }, + "node_modules/vite-svg-loader": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/vite-svg-loader/-/vite-svg-loader-5.1.1.tgz", + "integrity": "sha512-RPzcXA/EpKJA0585x58DBgs7my2VfeJ+j2j1EoHY4Zh82Y7hV4cR1fElgy2aZi85+QSrcLLoTStQ5uZjD68u+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "svgo": "^3.3.3" + }, + "peerDependencies": { + "vue": ">=3.2.13" + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vue": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", + "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-sfc": "3.5.35", + "@vue/runtime-dom": "3.5.35", + "@vue/server-renderer": "3.5.35", + "@vue/shared": "3.5.35" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.3.3.tgz", + "integrity": "sha512-x4nsFpy5Pe8fqPzp/5vkTPeTTDBpAx4WVtV47Ejt0+2FQrq4pRRsJs7JmYRqMFzTu/LW+pCWEjQ3YVCkPV7f9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/vue3-apexcharts": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.11.1.tgz", + "integrity": "sha512-MbN3vg8bMG19wc0Lm1HkeQvODgLm56DgpIxtNUO0xpf/JCzYWVGE4jzXp2JISzy2s3Kul1yOxNQUYsLvKQ5L9g==", + "peerDependencies": { + "apexcharts": ">=5.10.0", + "vue": ">=3.0.0" + }, + "peerDependenciesMeta": { + "apexcharts": { + "optional": false + } + } + }, + "node_modules/vue3-perfect-scrollbar": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vue3-perfect-scrollbar/-/vue3-perfect-scrollbar-2.0.0.tgz", + "integrity": "sha512-nSWVcRyViCgt0Pe3RhU3w/BllLcFSrEzYOGlRBjSyhVmiZlERHHziffW+9P8L0IMEWouC5t+uYrgNJGSAElqMA==", + "dependencies": { + "perfect-scrollbar": "^1.5.5" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vuetify": { + "version": "3.12.8", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.12.8.tgz", + "integrity": "sha512-gvmOWeLd6CG7LVh2Qonft5YrIb7MpbKZglRjg0ItEloSbu6hfUII2RZmRSVxGKYdiXTf7J1hI3BRSHr8J9LkxA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/johnleider" + }, + "peerDependencies": { + "typescript": ">=4.7", + "vite-plugin-vuetify": ">=2.1.0", + "vue": "^3.5.0", + "webpack-plugin-vuetify": ">=3.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vite-plugin-vuetify": { + "optional": true + }, + "webpack-plugin-vuetify": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/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/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/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/wrap-ansi-cjs/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/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/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/wrap-ansi/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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/admin/package.json b/src/admin/package.json old mode 100644 new mode 100755 index 4b61b66..3e016ce --- a/src/admin/package.json +++ b/src/admin/package.json @@ -1,41 +1,51 @@ -{ - "name": "mic-check-admin", - "version": "1.0.0", - "private": true, - "scripts": { - "build": "vite build", - "build:dev": "vite build --mode development", - "serve": "vite", - "preview": "vite preview", - "test": "jest --passWithNoTests" - }, - "dependencies": { - "@mdi/js": "^7.4.47", - "axios": "^1.15.0", - "pinia": "^3.0.4", - "vue": "^3.4.0", - "vue-router": "^4.3.0", - "vuetify": "^3.6.0" - }, - "devDependencies": { - "@babel/core": "^7.24.0", - "@babel/preset-env": "^7.24.0", - "@babel/preset-typescript": "^7.24.0", - "@types/jest": "^29.5.12", - "@types/node": "^20.12.0", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/test-utils": "^2.4.6", - "@vue/vue3-jest": "^29.2.6", - "babel-jest": "^29.7.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "sass": "^1.77.2", - "ts-jest": "^29.1.4", - "typescript": "^5.4.5", - "vite": "^8.0.8", - "vite-plugin-vuetify": "^2.1.3" - }, - "overrides": { - "brace-expansion": "^5.0.5" - } -} +{ + "name": "mic-check-admin", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "vite build", + "build:dev": "vite build --mode development", + "serve": "vite", + "preview": "vite preview", + "test": "jest --passWithNoTests" + }, + "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@iconify-json/bxl": "^1.2.0", + "@iconify-json/ri": "^1.2.0", + "@iconify/vue": "^4.1.0", + "@vueuse/core": "^11.0.0", + "apexcharts": "^5.15.0", + "axios": "^1.15.0", + "pinia": "^3.0.4", + "vue": "^3.4.0", + "vue-router": "^4.3.0", + "vue3-apexcharts": "^1.11.1", + "vue3-perfect-scrollbar": "^2.0.0", + "vuetify": "^3.7.5" + }, + "devDependencies": { + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", + "@babel/preset-typescript": "^7.24.0", + "@types/jest": "^29.5.12", + "@types/node": "^20.12.0", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/test-utils": "^2.4.6", + "@vue/vue3-jest": "^29.2.6", + "babel-jest": "^29.7.0", + "eslint": "^10.4.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "sass": "^1.77.2", + "sass-embedded": "^1.77.0", + "ts-jest": "^29.1.4", + "typescript": "^5.4.5", + "vite": "^8.0.8", + "vite-plugin-vuetify": "^2.1.3", + "vite-svg-loader": "^5.1.0" + }, + "overrides": { + "brace-expansion": "^5.0.5" + } +} diff --git a/src/admin/src/@core/components/MoreBtn.vue b/src/admin/src/@core/components/MoreBtn.vue new file mode 100755 index 0000000..46ed5ac --- /dev/null +++ b/src/admin/src/@core/components/MoreBtn.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/admin/src/@core/components/ThemeSwitcher.vue b/src/admin/src/@core/components/ThemeSwitcher.vue new file mode 100755 index 0000000..96712ac --- /dev/null +++ b/src/admin/src/@core/components/ThemeSwitcher.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/admin/src/@core/components/cards/CardStatisticsHorizontal.vue b/src/admin/src/@core/components/cards/CardStatisticsHorizontal.vue new file mode 100755 index 0000000..d17bcb2 --- /dev/null +++ b/src/admin/src/@core/components/cards/CardStatisticsHorizontal.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/admin/src/@core/components/cards/CardStatisticsVertical.vue b/src/admin/src/@core/components/cards/CardStatisticsVertical.vue new file mode 100755 index 0000000..9c3b297 --- /dev/null +++ b/src/admin/src/@core/components/cards/CardStatisticsVertical.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/admin/src/@core/components/cards/CardStatisticsWithImages.vue b/src/admin/src/@core/components/cards/CardStatisticsWithImages.vue new file mode 100755 index 0000000..1d2094d --- /dev/null +++ b/src/admin/src/@core/components/cards/CardStatisticsWithImages.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/src/admin/src/@core/scss/base/_components.scss b/src/admin/src/@core/scss/base/_components.scss new file mode 100755 index 0000000..3932a93 --- /dev/null +++ b/src/admin/src/@core/scss/base/_components.scss @@ -0,0 +1,191 @@ +@use "mixins"; +@use "@layouts/styles/placeholders"; +@use "@layouts/styles/mixins" as layoutMixins; +@use "@configured-variables" as variables; +@use "@styles/variables/_vuetify.scss" as vuetify; + +// 👉 Avatar group +.v-avatar-group { + display: flex; + align-items: center; + + > * { + &:not(:first-child) { + margin-inline-start: -0.8rem; + } + + transition: transform 0.25s ease, box-shadow 0.15s ease; + + &:hover { + z-index: 2; + transform: translateY(-5px) scale(1.05); + + @include mixins.elevation(3); + } + } + + > .v-avatar { + border: 2px solid rgb(var(--v-theme-surface)); + transition: transform 0.15s ease; + } +} + +// 👉 Button outline with default color border color +.v-alert--variant-outlined, +.v-avatar--variant-outlined, +.v-btn.v-btn--variant-outlined, +.v-card--variant-outlined, +.v-chip--variant-outlined, +.v-list-item--variant-outlined { + &:not([class*="text-"]) { + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + } + + &.text-default { + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + } +} + +// 👉 Custom Input +.v-label.custom-input { + padding: 1rem; + border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + opacity: 1; + white-space: normal; + + &:hover { + border-color: rgba(var(--v-border-color), 0.25); + } + + &.active { + border-color: rgb(var(--v-theme-primary)); + + .v-icon { + color: rgb(var(--v-theme-primary)) !important; + } + } + + &.custom-checkbox, + &.custom-radio { + .v-input__control { + grid-area: none; + } + } +} + +// 👉 Datatable +.v-data-table-footer__pagination { + @include layoutMixins.rtl { + .v-btn { + .v-icon { + transform: rotate(180deg); + } + } + } +} + +// Dialog responsive width +.v-dialog { + // dialog custom close btn + .v-dialog-close-btn { + position: absolute; + z-index: 1; + color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)) !important; + inset-block-start: 0.5rem; + inset-inline-end: 0.5rem; + + .v-btn__overlay { + display: none; + } + } + + .v-card { + @extend %style-scroll-bar; + } +} + +@media (min-width: 600px) { + .v-dialog { + &.v-dialog-sm, + &.v-dialog-lg, + &.v-dialog-xl { + .v-overlay__content { + inline-size: 565px !important; + } + } + } +} + +@media (min-width: 960px) { + .v-dialog { + &.v-dialog-lg, + &.v-dialog-xl { + .v-overlay__content { + inline-size: 865px !important; + } + } + } +} + +@media (min-width: 1264px) { + .v-dialog.v-dialog-xl { + .v-overlay__content { + inline-size: 1165px !important; + } + } +} + +// 👉 Expansion panel +.v-expansion-panels.customized-panels { + border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + border-radius: vuetify.$border-radius-root; + + .v-expansion-panel-title { + background-color: rgb(var(--v-theme-expansion-panel-text-custom-bg)); + border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + margin-block-end: -1px; + } + + .v-expansion-panel-text__wrapper { + padding: 20px; + } +} + +// v-tab with pill support +.v-tabs.v-tabs-pill { + .v-tab.v-btn { + border-radius: 0.25rem !important; + transition: none; + + .v-tab__slider { + visibility: hidden; + } + } +} + +// loop for all colors bg +@each $color-name in variables.$theme-colors-name { + body .v-tabs.v-tabs-pill { + .v-slide-group__content { + gap: 0.25rem; + } + .v-tab--selected.text-#{$color-name} { + background-color: rgb(var(--v-theme-#{$color-name})); + color: rgb(var(--v-theme-on-#{$color-name})) !important; + } + } +} + +// ℹ️ We are make even width of all v-timeline body +.v-timeline--vertical.v-timeline { + .v-timeline-item { + .v-timeline-item__body { + justify-self: stretch !important; + } + } +} + +// 👉 Switch +.v-switch .v-selection-control:not(.v-selection-control--dirty) .v-switch__thumb { + color: #fff !important; +} diff --git a/src/admin/src/@core/scss/base/_dark.scss b/src/admin/src/@core/scss/base/_dark.scss new file mode 100755 index 0000000..e92ab44 --- /dev/null +++ b/src/admin/src/@core/scss/base/_dark.scss @@ -0,0 +1,16 @@ +@use "@configured-variables" as variables; + +// ———————————————————————————————————— +// * ——— Perfect Scrollbar +// ———————————————————————————————————— + +body.v-theme--dark { + .ps__rail-y, + .ps__rail-x { + background-color: transparent !important; + } + + .ps__thumb-y { + background-color: variables.$plugin-ps-thumb-y-dark; + } +} diff --git a/src/admin/src/@core/scss/base/_default-layout-w-vertical-nav.scss b/src/admin/src/@core/scss/base/_default-layout-w-vertical-nav.scss new file mode 100755 index 0000000..1812fe2 --- /dev/null +++ b/src/admin/src/@core/scss/base/_default-layout-w-vertical-nav.scss @@ -0,0 +1,103 @@ +@use "@configured-variables" as variables; +@use "@core/scss/base/placeholders" as *; +@use "@core/scss/template/placeholders" as *; +@use "misc"; +@use "@core/scss/base/mixins"; + +$header: ".layout-navbar"; + +@if variables.$layout-vertical-nav-navbar-is-contained { + $header: ".layout-navbar .navbar-content-container"; +} + +.layout-wrapper.layout-nav-type-vertical { + // SECTION Layout Navbar + // 👉 Elevated navbar + @if variables.$vertical-nav-navbar-style == "elevated" { + // Add transition + #{$header} { + transition: padding 0.2s ease, background-color 0.18s ease; + } + + // If navbar is contained => Add border radius to header + @if variables.$layout-vertical-nav-navbar-is-contained { + #{$header} { + border-radius: 0 0 variables.$default-layout-with-vertical-nav-navbar-footer-roundness variables.$default-layout-with-vertical-nav-navbar-footer-roundness; + } + } + + // Scrolled styles for sticky navbar + @at-root { + /* ℹ️ This html selector with not selector is required when: + dialog is opened and window don't have any scroll. This removes window-scrolled class from layout and our style broke + */ + html.v-overlay-scroll-blocked:not([style*="--v-body-scroll-y: 0px;"]) .layout-navbar-sticky, + &.window-scrolled.layout-navbar-sticky { + + #{$header} { + @extend %default-layout-vertical-nav-scrolled-sticky-elevated-nav; + @extend %default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled; + } + + .navbar-blur#{$header} { + @extend %blurry-bg; + } + } + } + } + + // 👉 Floating navbar + @else if variables.$vertical-nav-navbar-style == "floating" { + // ℹ️ Regardless of navbar is contained or not => Apply overlay to .layout-navbar + .layout-navbar { + &.navbar-blur { + @extend %default-layout-vertical-nav-floating-navbar-overlay; + } + } + + &:not(.layout-navbar-sticky) { + #{$header} { + margin-block-start: variables.$vertical-nav-floating-navbar-top; + } + } + + #{$header} { + @if variables.$layout-vertical-nav-navbar-is-contained { + border-radius: variables.$default-layout-with-vertical-nav-navbar-footer-roundness; + } + + background-color: rgb(var(--v-theme-surface)); + + @extend %default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled; + } + + .navbar-blur#{$header} { + @extend %blurry-bg; + } + } + + // !SECTION + + // 👉 Layout footer + .layout-footer { + $ele-layout-footer: &; + + .footer-content-container { + border-radius: variables.$default-layout-with-vertical-nav-navbar-footer-roundness variables.$default-layout-with-vertical-nav-navbar-footer-roundness 0 0; + + // Sticky footer + @at-root { + // ℹ️ .layout-footer-sticky#{$ele-layout-footer} => .layout-footer-sticky.layout-wrapper.layout-nav-type-vertical .layout-footer + .layout-footer-sticky#{$ele-layout-footer} { + .footer-content-container { + background-color: rgb(var(--v-theme-surface)); + padding-block: 0; + padding-inline: 1.2rem; + + @include mixins.elevation(3); + } + } + } + } + } +} diff --git a/src/admin/src/@core/scss/base/_default-layout.scss b/src/admin/src/@core/scss/base/_default-layout.scss new file mode 100755 index 0000000..9794e7c --- /dev/null +++ b/src/admin/src/@core/scss/base/_default-layout.scss @@ -0,0 +1,16 @@ +@use "@core/scss/base/placeholders"; +@use "@core/scss/base/variables"; + +.layout-vertical-nav, +.layout-horizontal-nav { + ol, + ul { + list-style: none; + } +} + +.layout-navbar { + @if variables.$navbar-high-emphasis-text { + @extend %layout-navbar; + } +} diff --git a/src/admin/src/@core/scss/base/_index.scss b/src/admin/src/@core/scss/base/_index.scss new file mode 100755 index 0000000..9eb8a9c --- /dev/null +++ b/src/admin/src/@core/scss/base/_index.scss @@ -0,0 +1,40 @@ +@use "sass:map"; + +// Layout +@use "vertical-nav"; +@use "default-layout"; +@use "default-layout-w-vertical-nav"; + +// Layouts package +@use "layouts"; + +// Components +@use "components"; + +// Utilities +@use "utilities"; + +// Misc +@use "misc"; + +// Dark +@use "dark"; + +// libs +@use "libs/perfect-scrollbar"; + +a { + color: rgb(var(--v-theme-primary)); + text-decoration: none; +} + +// Vuetify 3 don't provide margin bottom style like vuetify 2 +p { + margin-block-end: 1rem; +} + +// Iconify icon size +svg.iconify { + block-size: 1em; + inline-size: 1em; +} diff --git a/src/admin/src/@core/scss/base/_layouts.scss b/src/admin/src/@core/scss/base/_layouts.scss new file mode 100755 index 0000000..f63fcf9 --- /dev/null +++ b/src/admin/src/@core/scss/base/_layouts.scss @@ -0,0 +1,63 @@ +@use "@configured-variables" as variables; + +/* ℹ️ This styles extends the existing layout package's styles for handling cases that aren't related to layouts package */ + +/* + ℹ️ When we use v-layout as immediate first child of `.page-content-container`, it adds display:flex and page doesn't get contained height +*/ +// .layout-wrapper.layout-nav-type-vertical { +// &.layout-content-height-fixed { +// .page-content-container { +// > .v-layout:first-child > :not(.v-navigation-drawer):first-child { +// flex-grow: 1; +// block-size: 100%; +// } +// } +// } +// } +.layout-wrapper.layout-nav-type-vertical { + &.layout-content-height-fixed { + .page-content-container { + > .v-layout:first-child { + overflow: hidden; + min-block-size: 100%; + + > .v-main { + // overflow-y: auto; + + .v-main__wrap > :first-child { + block-size: 100%; + overflow-y: auto; + } + } + } + } + } +} + +// ℹ️ Let div/v-layout take full height. E.g. Email App +.layout-wrapper.layout-nav-type-horizontal { + &.layout-content-height-fixed { + > .layout-page-content { + display: flex; + } + } +} + +// 👉 Floating navbar styles +@if variables.$vertical-nav-navbar-style == "floating" { + // ℹ️ Add spacing above navbar if navbar is floating (was in %layout-navbar-sticky placeholder) + body .layout-wrapper.layout-nav-type-vertical.layout-navbar-sticky { + .layout-navbar { + inset-block-start: variables.$vertical-nav-floating-navbar-top; + } + + /* + ℹ️ If it's floating navbar + Add `vertical-nav-floating-navbar-top` as margin top to .layout-page-content + */ + .layout-page-content { + margin-block-start: variables.$vertical-nav-floating-navbar-top; + } + } +} diff --git a/src/admin/src/@core/scss/base/_misc.scss b/src/admin/src/@core/scss/base/_misc.scss new file mode 100755 index 0000000..cee983b --- /dev/null +++ b/src/admin/src/@core/scss/base/_misc.scss @@ -0,0 +1,20 @@ +// ℹ️ scrollable-content allows creating fixed header and scrollable content for VNavigationDrawer (Used when perfect scrollbar is used) +.scrollable-content { + &.v-navigation-drawer { + .v-navigation-drawer__content { + display: flex; + overflow: hidden; + flex-direction: column; + } + } +} + +// ℹ️ adding styling for code tag +code { + border-radius: 3px; + color: rgb(var(--v-code-color)); + font-size: 90%; + font-weight: 400; + padding-block: 0.2em; + padding-inline: 0.4em; +} diff --git a/src/admin/src/@core/scss/base/_mixins.scss b/src/admin/src/@core/scss/base/_mixins.scss new file mode 100755 index 0000000..10ac1d1 --- /dev/null +++ b/src/admin/src/@core/scss/base/_mixins.scss @@ -0,0 +1,63 @@ +@use "sass:map"; +@use "@styles/variables/vuetify.scss"; + +@mixin elevation($z, $important: false) { + box-shadow: map.get(vuetify.$shadow-key-umbra, $z), map.get(vuetify.$shadow-key-penumbra, $z), map.get(vuetify.$shadow-key-ambient, $z) if($important, !important, null); +} + +// #region before-pseudo +// ℹ️ This mixin is inspired from vuetify for adding hover styles via before pseudo element +@mixin before-pseudo() { + position: relative; + + &::before { + position: absolute; + border-radius: inherit; + background: currentcolor; + block-size: 100%; + content: ""; + inline-size: 100%; + inset: 0; + opacity: 0; + pointer-events: none; + } +} + +// #endregion before-pseudo + +@mixin bordered-skin($component, $border-property: "border", $important: false) { + #{$component} { + box-shadow: none !important; + // stylelint-disable-next-line annotation-no-unknown + #{$border-property}: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)) if($important, !important, null); + } +} + +// #region selected-states +// ℹ️ Inspired from vuetify's active-states mixin +// focus => 0.12 & selected => 0.08 +@mixin selected-states($selector) { + #{$selector} { + opacity: calc(var(--v-selected-opacity) * var(--v-theme-overlay-multiplier)); + } + + &:hover + #{$selector} { + opacity: calc(var(--v-selected-opacity) + var(--v-hover-opacity) * var(--v-theme-overlay-multiplier)); + } + + &:focus-visible + #{$selector} { + opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier)); + } + + @supports not selector(:focus-visible) { + &:focus { + #{$selector} { + opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier)); + } + } + } +} + +// #endregion selected-states diff --git a/src/admin/src/@core/scss/base/_utilities.scss b/src/admin/src/@core/scss/base/_utilities.scss new file mode 100755 index 0000000..d629a63 --- /dev/null +++ b/src/admin/src/@core/scss/base/_utilities.scss @@ -0,0 +1,184 @@ +@use "@configured-variables" as variables; +@use "@layouts/styles/mixins" as layoutsMixins; + +/* 👉 Demo spacers */ + +/* TODO: Use vuetify SCSS variable here; */ +$card-spacer-content: 16px; + +.demo-space-x { + display: flex; + flex-wrap: wrap; + align-items: center; + margin-block-start: -$card-spacer-content; + + & > * { + margin-block-start: $card-spacer-content; + margin-inline-end: $card-spacer-content; + } +} + +.demo-space-y { + & > * { + margin-block-end: $card-spacer-content; + + &:last-child { + margin-block-end: 0; + } + } +} + +// 👉 Card match height +.match-height.v-row { + .v-card { + block-size: 100%; + } +} + +// 👉 Whitespace +.whitespace-no-wrap { + white-space: nowrap; +} + +// 👉 Colors + +/* + ℹ️ Vuetify is applying `.text-white` class to badge icon but don't provide its styles + Moreover, we also use this class in some places + + ℹ️ In vuetify 2 with `$color-pack: false` SCSS var config this class was getting generated but this is not the case in v3 + + ℹ️ We also need !important to get correct color in badge icon +*/ +.text-white { + color: #fff !important; +} + +.text-white-variant { + color: rgba(255, 255, 255, var(--v-high-emphasis-opacity)); +} + +.text-link { + &:not(:hover) { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + } +} + +.bg-var-theme-background { + background-color: rgba(var(--v-theme-on-background), var(--v-hover-opacity)) !important; +} + +.bg-global-primary { + background-color: rgb(var(--v-theme-primary)) !important; + color: rgb(var(--v-theme-on-primary)) !important; +} + +// [/^bg-light-(\w+)$/, ([, w]) => ({ backgroundColor: `rgba(var(--v-theme-${w}), var(--v-activated-opacity))` })], +@each $color-name in variables.$theme-colors-name { + .bg-light-#{$color-name} { + background-color: rgba(var(--v-theme-#{$color-name}), var(--v-activated-opacity)) !important; + } +} + +// 👉 clamp text +.clamp-text { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; +} + +.custom-badge { + .v-badge__badge { + border-radius: 6px !important; + block-size: 12px !important; + inline-size: 12px !important; + } +} + +.leading-normal { + line-height: normal !important; +} + +// 👉 for rtl only +.flip-in-rtl { + @include layoutsMixins.rtl { + transform: scaleX(-1); + } +} + +// 👉 Carousel +.carousel-delimiter-top-end { + .v-carousel__controls { + justify-content: end; + block-size: 40px; + inset-block-start: 0; + padding-inline: 1rem; + + .v-btn--icon.v-btn--density-default { + block-size: calc(var(--v-btn-height) + -10px); + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + inline-size: calc(var(--v-btn-height) + -8px); + + &.v-btn--active { + color: #fff; + } + + .v-btn__overlay { + opacity: 0; + } + + .v-ripple__container { + display: none; + } + + .v-btn__content { + .v-icon { + block-size: 8px !important; + font-size: 8px !important; + inline-size: 8px !important; + } + } + } + } + + @each $color-name in variables.$theme-colors-name { + + &.dots-active-#{$color-name} { + .v-carousel__controls { + .v-btn--active { + color: rgb(var(--v-theme-#{$color-name})) !important; + } + } + } + } +} + +.v-timeline-item { + .app-timeline-title { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + font-size: 16px; + font-weight: 500; + line-height: 1.3125rem; + } + + .app-timeline-meta { + color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)); + font-size: 12px; + line-height: 0.875rem; + } + + .app-timeline-text { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + font-size: 14px; + line-height: 1.25rem; + } + + .timeline-chip { + border-radius: 6px; + background: rgba(var(--v-theme-on-surface), var(--v-hover-opacity)); + padding-block: 5px; + padding-inline: 10px; + } +} diff --git a/src/admin/src/@core/scss/base/_utils.scss b/src/admin/src/@core/scss/base/_utils.scss new file mode 100755 index 0000000..02acb62 --- /dev/null +++ b/src/admin/src/@core/scss/base/_utils.scss @@ -0,0 +1,90 @@ +@use "sass:map"; +@use "sass:list"; +@use "@configured-variables" as variables; + +// Thanks: https://css-tricks.com/snippets/sass/deep-getset-maps/ +@function map-deep-get($map, $keys...) { + @each $key in $keys { + $map: map.get($map, $key); + } + + @return $map; +} + +@function map-deep-set($map, $keys, $value) { + $maps: ($map,); + $result: null; + + // If the last key is a map already + // Warn the user we will be overriding it with $value + @if type-of(nth($keys, -1)) == "map" { + @warn "The last key you specified is a map; it will be overrided with `#{$value}`."; + } + + // If $keys is a single key + // Just merge and return + @if length($keys) == 1 { + @return map-merge($map, ($keys: $value)); + } + + // Loop from the first to the second to last key from $keys + // Store the associated map to this key in the $maps list + // If the key doesn't exist, throw an error + @for $i from 1 through length($keys) - 1 { + $current-key: list.nth($keys, $i); + $current-map: list.nth($maps, -1); + $current-get: map.get($current-map, $current-key); + + @if not $current-get { + @error "Key `#{$key}` doesn't exist at current level in map."; + } + + $maps: list.append($maps, $current-get); + } + + // Loop from the last map to the first one + // Merge it with the previous one + @for $i from length($maps) through 1 { + $current-map: list.nth($maps, $i); + $current-key: list.nth($keys, $i); + $current-val: if($i == list.length($maps), $value, $result); + $result: map.map-merge($current-map, ($current-key: $current-val)); + } + + // Return result + @return $result; +} + +// font size utility classes +@each $name, $size in variables.$font-sizes { + .text-#{$name} { + font-size: $size; + line-height: map.get(variables.$font-line-height, $name); + } +} + +// truncate utility class +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +// gap utility class +@each $name, $size in variables.$gap { + .gap-#{$name} { + gap: $size; + } + + .gap-x-#{$name} { + column-gap: $size; + } + + .gap-y-#{$name} { + row-gap: $size; + } +} + +.list-none { + list-style-type: none; +} diff --git a/src/admin/src/@core/scss/base/_variables.scss b/src/admin/src/@core/scss/base/_variables.scss new file mode 100755 index 0000000..670a1a2 --- /dev/null +++ b/src/admin/src/@core/scss/base/_variables.scss @@ -0,0 +1,198 @@ +@use "vuetify/lib/styles/tools/functions" as *; + +/* + TODO: Add docs on when to use placeholder vs when to use SASS variable + + Placeholder + - When we want to keep customization to our self between templates use it + + Variables + - When we want to allow customization from both user and our side + - You can also use variable for consistency (e.g. mx 1 rem should be applied to both vertical nav items and vertical nav header) +*/ + +@forward "@layouts/styles/variables" with ( + // Adjust z-index so vertical nav & overlay stays on top of v-layout in v-main. E.g. Email app + $layout-vertical-nav-z-index: 1003, + $layout-overlay-z-index: 1002, +); +@use "@layouts/styles/variables" as *; + +// 👉 Default layout + +$navbar-high-emphasis-text: true !default; + +// @forward "@layouts/styles/variables" with ( +// $layout-vertical-nav-width: 350px !default, +// ); + +$theme-colors-name: ( + "primary", + "secondary", + "error", + "info", + "success", + "warning" +) !default; + +// 👉 Default layout with vertical nav + +$default-layout-with-vertical-nav-navbar-footer-roundness: 10px !default; + +// 👉 Vertical nav +$vertical-nav-background-color-rgb: var(--v-theme-background) !default; +$vertical-nav-background-color: rgb(#{$vertical-nav-background-color-rgb}) !default; + +// ℹ️ This is used to keep consistency between nav items and nav header left & right margin +// This is used by nav items & nav header +$vertical-nav-horizontal-spacing: 1rem !default; +$vertical-nav-horizontal-padding: 0.75rem !default; + +// Vertical nav header height. Mostly we will align it with navbar height; +$vertical-nav-header-height: $layout-vertical-nav-navbar-height !default; +$vertical-nav-navbar-elevation: 3 !default; +$vertical-nav-navbar-style: "elevated" !default; // options: elevated, floating +$vertical-nav-floating-navbar-top: 1rem !default; + +// Vertical nav header padding +$vertical-nav-header-padding: 1rem $vertical-nav-horizontal-padding !default; +$vertical-nav-header-inline-spacing: $vertical-nav-horizontal-spacing !default; + +// Move logo when vertical nav is mini (collapsed but not hovered) +$vertical-nav-header-logo-translate-x-when-vertical-nav-mini: -4px !default; + +// Space between logo and title +$vertical-nav-header-logo-title-spacing: 0.9rem !default; + +// Section title margin top (when its not first child) +$vertical-nav-section-title-mt: 1.5rem !default; + +// Section title margin bottom +$vertical-nav-section-title-mb: 0.5rem !default; + +// Vertical nav icons +$vertical-nav-items-icon-size: 1.5rem !default; +$vertical-nav-items-nested-icon-size: 0.9rem !default; +$vertical-nav-items-icon-margin-inline-end: 0.5rem !default; + +// Transition duration for nav group arrow +$vertical-nav-nav-group-arrow-transition-duration: 0.15s !default; + +// Timing function for nav group arrow +$vertical-nav-nav-group-arrow-transition-timing-function: ease-in-out !default; + +// 👉 Horizontal nav + +/* + ❗ Heads up + ================== + Here we assume we will always use shorthand property which will apply same padding on four side + This is because this have been used as value of top property by `.popper-content` +*/ +$horizontal-nav-padding: 0.6875rem !default; + +// Gap between top level horizontal nav items +$horizontal-nav-top-level-items-gap: 4px !default; + +// Horizontal nav icons +$horizontal-nav-items-icon-size: 1.5rem !default; +$horizontal-nav-third-level-icon-size: 0.9rem !default; +$horizontal-nav-items-icon-margin-inline-end: 0.625rem !default; +$horizontal-nav-group-arrow-icon-size: 1.375rem !default; + +// ℹ️ We used SCSS variable because we want to allow users to update max height of popper content +// 120px is combined height of navbar & horizontal nav +$horizontal-nav-popper-content-max-height: calc(100dvh - 120px - 4rem) !default; + +// ℹ️ This variable is used for horizontal nav popper content's `margin-top` and "The bridge"'s height. We need to sync both values. +$horizontal-nav-popper-content-top: calc($horizontal-nav-padding + 0.375rem) !default; + +// 👉 Plugins + +$plugin-ps-thumb-y-dark: rgba(var(--v-theme-surface-variant), 0.35) !default; + +// 👉 Vuetify + +// Used in src/@core/scss/base/libs/vuetify/_overrides.scss +$vuetify-reduce-default-compact-button-icon-size: true !default; + +// 👉 Custom variables +// for utility classes +$font-sizes: () !default; +$font-sizes: map-deep-merge( + ( + "xs": 0.75rem, + "sm": 0.875rem, + "base": 1rem, + "lg": 1.125rem, + "xl": 1.25rem, + "2xl": 1.5rem, + "3xl": 1.875rem, + "4xl": 2.25rem, + "5xl": 3rem, + "6xl": 3.75rem, + "7xl": 4.5rem, + "8xl": 6rem, + "9xl": 8rem + ), + $font-sizes +); + +// line height +$font-line-height: () !default; +$font-line-height: map-deep-merge( + ( + "xs": 1rem, + "sm": 1.25rem, + "base": 1.5rem, + "lg": 1.75rem, + "xl": 1.75rem, + "2xl": 2rem, + "3xl": 2.25rem, + "4xl": 2.5rem, + "5xl": 1, + "6xl": 1, + "7xl": 1, + "8xl": 1, + "9xl": 1 + ), + $font-line-height +); + +// gap utility class +$gap: () !default; +$gap: map-deep-merge( + ( + "0": 0, + "1": 0.25rem, + "2": 0.5rem, + "3": 0.75rem, + "4": 1rem, + "5": 1.25rem, + "6":1.5rem, + "7": 1.75rem, + "8": 2rem, + "9": 2.25rem, + "10": 2.5rem, + "11": 2.75rem, + "12": 3rem, + "14": 3.5rem, + "16": 4rem, + "20": 5rem, + "24": 6rem, + "28": 7rem, + "32": 8rem, + "36": 9rem, + "40": 10rem, + "44": 11rem, + "48": 12rem, + "52": 13rem, + "56": 14rem, + "60": 15rem, + "64": 16rem, + "72": 18rem, + "80": 20rem, + "96": 24rem + ), + $gap +); diff --git a/src/admin/src/@core/scss/base/_vertical-nav.scss b/src/admin/src/@core/scss/base/_vertical-nav.scss new file mode 100755 index 0000000..9785944 --- /dev/null +++ b/src/admin/src/@core/scss/base/_vertical-nav.scss @@ -0,0 +1,259 @@ +@use "@core/scss/base/placeholders" as *; +@use "@core/scss/template/placeholders" as *; +@use "@layouts/styles/mixins" as layoutsMixins; +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins" as mixins; +@use "vuetify/lib/styles/tools/states" as vuetifyStates; + +.layout-nav-type-vertical { + // 👉 Layout Vertical nav + .layout-vertical-nav { + $sl-layout-nav-type-vertical: &; + + @extend %nav; + + @at-root { + // ℹ️ Add styles for collapsed vertical nav + .layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}.hovered { + @include mixins.elevation(6); + } + } + + background-color: variables.$vertical-nav-background-color; + + // 👉 Nav header + .nav-header { + overflow: hidden; + padding: variables.$vertical-nav-header-padding; + margin-inline: variables.$vertical-nav-header-inline-spacing; + min-block-size: variables.$vertical-nav-header-height; + + // TEMPLATE: Check if we need to move this to master + .app-logo { + flex-shrink: 0; + transition: transform 0.25s ease-in-out; + + @at-root { + // Move logo a bit to align center with the icons in vertical nav mini variant + .layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}:not(.hovered) .nav-header .app-logo { + transform: translateX(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini); + + @include layoutsMixins.rtl { + transform: translateX(-(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini)); + } + } + } + } + + .app-title { + margin-inline-start: variables.$vertical-nav-header-logo-title-spacing; + } + + .header-action { + @extend %nav-header-action; + } + } + + // 👉 Nav items shadow + .vertical-nav-items-shadow { + position: absolute; + z-index: 1; + background: + linear-gradient( + rgb(#{variables.$vertical-nav-background-color-rgb}) 5%, + rgba(#{variables.$vertical-nav-background-color-rgb}, 75%) 45%, + rgba(#{variables.$vertical-nav-background-color-rgb}, 20%) 80%, + transparent + ); + block-size: 55px; + inline-size: 100%; + inset-block-start: calc(#{variables.$vertical-nav-header-height} - 2px); + opacity: 0; + pointer-events: none; + transition: opacity 0.15s ease-in-out; + will-change: opacity; + + @include layoutsMixins.rtl { + transform: translateX(8px); + } + } + + &.scrolled { + .vertical-nav-items-shadow { + opacity: 1; + } + } + + // ℹ️ Setting z-index 1 will make perfect scrollbar thumb appear on top of vertical nav items shadow; + .ps__rail-y { + z-index: 1; + } + + // 👉 Nav section title + .nav-section-title { + @extend %vertical-nav-item; + @extend %vertical-nav-section-title; + + margin-block-end: variables.$vertical-nav-section-title-mb; + + &:not(:first-child) { + margin-block-start: variables.$vertical-nav-section-title-mt; + } + + .placeholder-icon { + margin-inline: auto; + } + } + + // Nav item badge + .nav-item-badge { + @extend %vertical-nav-item-badge; + } + + // 👉 Nav group & Link + .nav-link, + .nav-group { + overflow: hidden; + + > :first-child { + @extend %vertical-nav-item; + @extend %vertical-nav-item-interactive; + } + + .nav-item-icon { + @extend %vertical-nav-items-icon; + } + + &.disabled { + opacity: var(--v-disabled-opacity); + pointer-events: none; + } + + a { + outline: none; + } + } + + // 👉 Vertical nav link + .nav-link { + @extend %nav-link; + + > .router-link-exact-active { + @extend %nav-link-active; + } + + > a { + // Adds before psudo element to style hover state + @include mixins.before-pseudo; + + // Adds vuetify states + + &:not(.router-link-active, .router-link-exact-active) { + @include vuetifyStates.states($active: false); + } + } + } + + // 👉 Vertical nav group + .nav-group { + // Reduce the size of icon if link/group is inside group + .nav-group, + .nav-link { + .nav-item-icon { + @extend %vertical-nav-items-nested-icon; + } + } + + // Hide icons after 2nd level + & .nav-group { + .nav-link, + .nav-group { + .nav-item-icon { + @extend %vertical-nav-items-icon-after-2nd-level; + } + } + } + + .nav-group-arrow { + flex-shrink: 0; + transform-origin: center; + transition: transform variables.$vertical-nav-nav-group-arrow-transition-duration variables.$vertical-nav-nav-group-arrow-transition-timing-function; + will-change: transform; + } + + // Rotate arrow icon if group is opened + &.open { + > .nav-group-label .nav-group-arrow { + transform: rotateZ(90deg); + } + } + + // Nav group label + > :first-child { + // Adds before psudo element to style hover state + @include mixins.before-pseudo; + } + + &:not(.active,.open) > :first-child { + // Adds vuetify states + @include vuetifyStates.states($active: false); + } + + // Active & open states for nav group label + &.active, + &.open { + > :first-child { + @extend %vertical-nav-group-open-active; + } + } + } + } +} + +// SECTION: Transitions +.vertical-nav-section-title-enter-active, +.vertical-nav-section-title-leave-active { + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} + +.vertical-nav-section-title-enter-from, +.vertical-nav-section-title-leave-to { + opacity: 0; + transform: translateX(15px); + + @include layoutsMixins.rtl { + transform: translateX(-15px); + } +} + +.transition-slide-x-enter-active, +.transition-slide-x-leave-active { + transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out; +} + +.transition-slide-x-enter-from, +.transition-slide-x-leave-to { + opacity: 0; + transform: translateX(-15px); + + @include layoutsMixins.rtl { + transform: translateX(15px); + } +} + +.vertical-nav-app-title-enter-active, +.vertical-nav-app-title-leave-active { + transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out; +} + +.vertical-nav-app-title-enter-from, +.vertical-nav-app-title-leave-to { + opacity: 0; + transform: translateX(-15px); + + @include layoutsMixins.rtl { + transform: translateX(15px); + } +} + +// !SECTION diff --git a/src/admin/src/@core/scss/base/libs/_perfect-scrollbar.scss b/src/admin/src/@core/scss/base/libs/_perfect-scrollbar.scss new file mode 100755 index 0000000..126aea2 --- /dev/null +++ b/src/admin/src/@core/scss/base/libs/_perfect-scrollbar.scss @@ -0,0 +1,35 @@ +$ps-size: 0.25rem; +$ps-hover-size: 0.375rem; +$ps-track-size: 0.5rem; + +.ps__thumb-y { + inline-size: $ps-size !important; + inset-inline-end: 0.0625rem; +} + +.ps__thumb-y, +.ps__thumb-x { + background-color: rgb(var(--v-theme-perfect-scrollbar-thumb)) !important; +} + +.ps__thumb-x { + block-size: $ps-size !important; +} + +.ps__rail-x { + background: transparent !important; + block-size: $ps-track-size; +} + +.ps__rail-y { + background: transparent !important; + inline-size: $ps-track-size !important; + inset-inline-end: 0.125rem !important; + inset-inline-start: unset !important; +} + +.ps__rail-y.ps--clicking .ps__thumb-y, +.ps__rail-y:focus > .ps__thumb-y, +.ps__rail-y:hover > .ps__thumb-y { + inline-size: $ps-hover-size !important; +} diff --git a/src/admin/src/@core/scss/base/libs/vuetify/_index.scss b/src/admin/src/@core/scss/base/libs/vuetify/_index.scss new file mode 100755 index 0000000..f33ef3f --- /dev/null +++ b/src/admin/src/@core/scss/base/libs/vuetify/_index.scss @@ -0,0 +1 @@ +@use "overrides"; diff --git a/src/admin/src/@core/scss/base/libs/vuetify/_overrides.scss b/src/admin/src/@core/scss/base/libs/vuetify/_overrides.scss new file mode 100755 index 0000000..632912b --- /dev/null +++ b/src/admin/src/@core/scss/base/libs/vuetify/_overrides.scss @@ -0,0 +1,257 @@ +@use "@core/scss/base/utils"; +@use "@configured-variables" as variables; + +// 👉 Application +// ℹ️ We need accurate vh in mobile devices as well +.v-application__wrap { + /* stylelint-disable-next-line liberty/use-logical-spec */ + min-height: 100dvh; +} + +// 👉 Typography +h1, +h2, +h3, +h4, +h5, +h6, +.text-h1, +.text-h2, +.text-h3, +.text-h4, +.text-h5, +.text-h6, +.text-button, +.text-overline, +.v-card-title { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); +} + +body, +.text-body-1, +.text-body-2, +.text-subtitle-1, +.text-subtitle-2 { + color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity)); +} + +// 👉 Grid +// Remove margin-bottom of v-input_details inside grid (validation error message) +.v-row { + .v-col, + [class^="v-col-*"] { + .v-input__details { + margin-block-end: 0; + } + } +} + +// 👉 Button +@if variables.$vuetify-reduce-default-compact-button-icon-size { + .v-btn--density-compact.v-btn--size-default { + .v-btn__content > svg { + block-size: 22px; + font-size: 22px; + inline-size: 22px; + } + } +} + +// 👉 Card +// Removes padding-top for immediately placed v-card-text after itself +.v-card-text { + & + & { + padding-block-start: 0 !important; + } +} + +/* + 👉 Checkbox & Radio Ripple + + TODO Checkbox and switch component. Remove it when vuetify resolve the extra spacing: https://github.com/vuetifyjs/vuetify/issues/15519 + We need this because form elements likes checkbox and switches are by default set to height of textfield height which is way big than we want + Tested with checkbox & switches +*/ +.v-checkbox.v-input, +.v-switch.v-input { + --v-input-control-height: auto; + + flex: unset; +} + +.v-radio-group { + .v-selection-control-group { + .v-radio:not(:last-child) { + margin-inline-end: 0.9rem; + } + } +} + +/* + 👉 Tabs + Disable tab transition + + This is for tabs where we don't have card wrapper to tabs and have multiple cards as tab content. + + This class will disable transition and adds `overflow: unset` on `VWindow` to allow spreading shadow +*/ +.disable-tab-transition { + overflow: unset !important; + + .v-window__container { + block-size: auto !important; + } + + .v-window-item:not(.v-window-item--active) { + display: none !important; + } + + .v-window__container .v-window-item { + transform: none !important; + } +} + +// 👉 List +.v-list { + // Set icons opacity to .87 + .v-list-item__prepend > .v-icon, + .v-list-item__append > .v-icon { + opacity: var(--v-high-emphasis-opacity); + } +} + +// 👉 Card list + +/* + ℹ️ Custom class + + Remove list spacing inside card + + This is because card title gets padding of 20px and list item have padding of 16px. Moreover, list container have padding-bottom as well. +*/ +.card-list { + --v-card-list-gap: 20px; + + &.v-list { + padding-block: 0; + } + + .v-list-item { + min-block-size: unset; + min-block-size: auto !important; + padding-block: 0 !important; + padding-inline: 0 !important; + + > .v-ripple__container { + opacity: 0; + } + + &:not(:last-child) { + padding-block-end: var(--v-card-list-gap) !important; + } + } + + .v-list-item:hover, + .v-list-item:focus, + .v-list-item:active, + .v-list-item.active { + > .v-list-item__overlay { + opacity: 0 !important; + } + } +} + +// 👉 Divider +.v-divider { + color: rgb(var(--v-border-color)); +} + +.v-divider.v-divider--vertical { + block-size: inherit; +} + +// 👉 DataTable +.v-data-table { + /* stylelint-disable-next-line no-descending-specificity */ + .v-checkbox-btn .v-selection-control__wrapper { + margin-inline-start: 0 !important; + } + + .v-selection-control { + display: flex !important; + } + + .v-pagination { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + } +} + +// 👉 v-field +.v-field:hover .v-field__outline { + --v-field-border-opacity: var(--v-medium-emphasis-opacity); +} + +// 👉 VLabel +.v-label { + opacity: 1 !important; + + &:not(.v-field-label--floating) { + color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity)); + } +} + +// 👉 Overlay +.v-overlay__scrim, +.v-navigation-drawer__scrim { + background: rgba(var(--v-overlay-scrim-background), var(--v-overlay-scrim-opacity)) !important; + opacity: 1 !important; +} + +// 👉 VMessages +.v-messages { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + opacity: 1 !important; +} + +// 👉 Alert close btn +.v-alert__close { + .v-btn--icon .v-icon { + --v-icon-size-multiplier: 1.5; + } +} + +// 👉 Badge icon alignment +.v-badge__badge { + display: flex; + align-items: center; +} + +// 👉 Btn focus outline style removed +.v-btn:focus-visible::after { + opacity: 0 !important; +} + +// .v-select chip spacing for slot +.v-input:not(.v-select--chips) .v-select__selection { + .v-chip { + margin-block: 2px var(--select-chips-margin-bottom); + } +} + +// 👉 VCard and VList subtitle color +.v-card-subtitle, +.v-list-item-subtitle { + color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity)); +} + +// 👉 placeholders +.v-field__input { + @at-root { + & input::placeholder, + input#{&}::placeholder, + textarea#{&}::placeholder { + color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)) !important; + opacity: 1 !important; + } + } +} diff --git a/src/admin/src/@core/scss/base/libs/vuetify/_variables.scss b/src/admin/src/@core/scss/base/libs/vuetify/_variables.scss new file mode 100755 index 0000000..0719d00 --- /dev/null +++ b/src/admin/src/@core/scss/base/libs/vuetify/_variables.scss @@ -0,0 +1,64 @@ +@use "sass:map"; + +/* 👉 Shadow opacities */ +$shadow-key-umbra-opacity-custom: var(--v-shadow-key-umbra-opacity); +$shadow-key-penumbra-opacity-custom: var(--v-shadow-key-penumbra-opacity); +$shadow-key-ambient-opacity-custom: var(--v-shadow-key-ambient-opacity); + +/* 👉 Card transition properties */ +$card-transition-property-custom: box-shadow, opacity; + +@forward "vuetify/settings" with ( + // 👉 General settings + $color-pack: false !default, + + // 👉 Shadow opacity + $shadow-key-umbra-opacity: $shadow-key-umbra-opacity-custom !default, + $shadow-key-penumbra-opacity: $shadow-key-penumbra-opacity-custom !default, + $shadow-key-ambient-opacity: $shadow-key-ambient-opacity-custom !default, + + // 👉 Card + $card-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default, + $card-elevation: 6 !default, + $card-title-line-height: 1.6 !default, + $card-actions-min-height: unset !default, + $card-text-padding: 1.25rem !default, + $card-item-padding: 1.25rem !default, + $card-actions-padding: 0 12px 12px !default, + $card-transition-property: $card-transition-property-custom !default, + $card-subtitle-opacity: 1 !default, + + // 👉 Expansion Panel + $expansion-panel-active-title-min-height: 48px !default, + + // 👉 List + $list-item-icon-margin-end: 16px !default, + $list-item-icon-margin-start: 16px !default, + $list-item-subtitle-opacity: 1 !default, + + // 👉 Navigation Drawer + $navigation-drawer-content-overflow-y: hidden !default, + + // 👉 Tooltip + $tooltip-background-color: rgba(59, 55, 68, 0.9) !default, + $tooltip-text-color: rgb(var(--v-theme-on-primary)) !default, + $tooltip-font-size: 0.75rem !default, + + $button-icon-density: ("default": 2, "comfortable": 0, "compact": -1 ) !default, + + // 👉 VTimeline + $timeline-dot-size: 34px !default, + + // 👉 table + $table-transition-property: height !default, + + // 👉 VOverlay + $overlay-opacity: 1 !default, + + // 👉 VContainer + $container-max-widths: ( + "xl": 1440px, + "xxl": 1440px + ) !default, + +); diff --git a/src/admin/src/@core/scss/base/placeholders/_default-layout-vertical-nav.scss b/src/admin/src/@core/scss/base/placeholders/_default-layout-vertical-nav.scss new file mode 100755 index 0000000..f449a59 --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_default-layout-vertical-nav.scss @@ -0,0 +1,45 @@ +@use "@configured-variables" as variables; +@use "misc"; +@use "@core/scss/base/mixins"; + +%default-layout-vertical-nav-scrolled-sticky-elevated-nav { + background-color: rgb(var(--v-theme-surface)); +} + +%default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled { + @include mixins.elevation(variables.$vertical-nav-navbar-elevation); + + // If navbar is contained => Squeeze navbar content on scroll + @if variables.$layout-vertical-nav-navbar-is-contained { + padding-inline: 1.2rem; + } +} + +%default-layout-vertical-nav-floating-navbar-overlay { + isolation: isolate; + + &::after { + position: absolute; + z-index: -1; + /* stylelint-disable property-no-vendor-prefix */ + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + /* stylelint-enable */ + background: + linear-gradient( + 180deg, + rgba(var(--v-theme-background), 70%) 44%, + rgba(var(--v-theme-background), 43%) 73%, + rgba(var(--v-theme-background), 0%) + ); + background-repeat: repeat; + block-size: calc(variables.$layout-vertical-nav-navbar-height + variables.$vertical-nav-floating-navbar-top + 0.5rem); + content: ""; + inset-block-start: -(variables.$vertical-nav-floating-navbar-top); + inset-inline: 0 0; + /* stylelint-disable property-no-vendor-prefix */ + -webkit-mask: linear-gradient(black, black 18%, transparent 100%); + mask: linear-gradient(black, black 18%, transparent 100%); + /* stylelint-enable */ + } +} diff --git a/src/admin/src/@core/scss/base/placeholders/_default-layout.scss b/src/admin/src/@core/scss/base/placeholders/_default-layout.scss new file mode 100755 index 0000000..8e5e990 --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_default-layout.scss @@ -0,0 +1,3 @@ +%layout-navbar { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); +} diff --git a/src/admin/src/@core/scss/base/placeholders/_index.scss b/src/admin/src/@core/scss/base/placeholders/_index.scss new file mode 100755 index 0000000..c59061a --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_index.scss @@ -0,0 +1,5 @@ +@forward "vertical-nav"; +@forward "nav"; +@forward "default-layout"; +@forward "default-layout-vertical-nav"; +@forward "misc"; diff --git a/src/admin/src/@core/scss/base/placeholders/_misc.scss b/src/admin/src/@core/scss/base/placeholders/_misc.scss new file mode 100755 index 0000000..87a3ed6 --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_misc.scss @@ -0,0 +1,7 @@ +%blurry-bg { + /* stylelint-disable property-no-vendor-prefix */ + -webkit-backdrop-filter: blur(6px); + backdrop-filter: blur(6px); + /* stylelint-enable */ + background-color: rgb(var(--v-theme-surface), 0.9); +} diff --git a/src/admin/src/@core/scss/base/placeholders/_nav.scss b/src/admin/src/@core/scss/base/placeholders/_nav.scss new file mode 100755 index 0000000..655535a --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_nav.scss @@ -0,0 +1,33 @@ +@use "@core/scss/base/mixins"; + +// ℹ️ This is common style that needs to be applied to both navs +%nav { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + + .nav-item-title { + letter-spacing: 0.15px; + } + + .nav-section-title { + letter-spacing: 0.4px; + } +} + +/* + Active nav link styles for horizontal & vertical nav + + For horizontal nav it will be only applied to top level nav items + For vertical nav it will be only applied to nav links (not nav groups) +*/ +%nav-link-active { + background-color: rgb(var(--v-theme-primary)); + color: rgb(var(--v-theme-on-primary)); + + @include mixins.elevation(3); +} + +%nav-link { + a { + color: inherit; + } +} diff --git a/src/admin/src/@core/scss/base/placeholders/_vertical-nav.scss b/src/admin/src/@core/scss/base/placeholders/_vertical-nav.scss new file mode 100755 index 0000000..3ad2a8c --- /dev/null +++ b/src/admin/src/@core/scss/base/placeholders/_vertical-nav.scss @@ -0,0 +1,80 @@ +@use "@core/scss/base/mixins"; +@use "@configured-variables" as variables; +@use "vuetify/lib/styles/tools/states" as vuetifyStates; + +%nav-header-action { + font-size: 1.25rem; +} + +// Nav items styles (including section title) +%vertical-nav-item { + margin-block: 0; + margin-inline: variables.$vertical-nav-horizontal-spacing; + padding-block: 0; + padding-inline: variables.$vertical-nav-horizontal-padding; + white-space: nowrap; +} + +// This is same as `%vertical-nav-item` except section title is excluded +%vertical-nav-item-interactive { + border-radius: 0.4rem; + block-size: 2.75rem; + + /* + ℹ️ We will use `margin-block-end` instead of `margin-block` to give more space for shadow to appear. + With `margin-block`, due to small space (space gets divided between top & bottom) shadow cuts + */ + margin-block-end: 0.375rem; +} + +// Common styles for nav item icon styles +// ℹ️ Nav group's children icon styles are not here (Adjusts height, width & margin) +%vertical-nav-items-icon { + flex-shrink: 0; + font-size: variables.$vertical-nav-items-icon-size; + margin-inline-end: variables.$vertical-nav-items-icon-margin-inline-end; +} + +// ℹ️ Icon styling for icon nested inside another nav item (2nd level) +%vertical-nav-items-nested-icon { + /* + ℹ️ `margin-inline` will be (normal icon font-size - small icon font-size) / 2 + (1.5rem - 0.9rem) / 2 => 0.6rem / 2 => 0.3rem + */ + $vertical-nav-items-nested-icon-margin-inline: calc((variables.$vertical-nav-items-icon-size - variables.$vertical-nav-items-nested-icon-size) / 2); + + font-size: variables.$vertical-nav-items-nested-icon-size; + margin-inline: $vertical-nav-items-nested-icon-margin-inline $vertical-nav-items-nested-icon-margin-inline + variables.$vertical-nav-items-icon-margin-inline-end; +} + +%vertical-nav-items-icon-after-2nd-level { + visibility: hidden; +} + +// Open & Active nav group styles +%vertical-nav-group-open-active { + @include mixins.selected-states("&::before"); +} + +// Section title +// ℹ️ Setting height will prevent jerking when text & icon is toggled +%vertical-nav-section-title { + block-size: 1.5rem; + color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)); + font-size: 0.75rem; + text-transform: uppercase; +} + +// Vertical nav item badge styles +%vertical-nav-item-badge { + display: inline-block; + border-radius: 1.5rem; + font-size: 0.8em; + font-weight: 500; + line-height: 1; + padding-block: 0.25em; + padding-inline: 0.55em; + text-align: center; + vertical-align: baseline; + white-space: nowrap; +} diff --git a/src/admin/src/@core/scss/template/_default-layout-w-vertical-nav.scss b/src/admin/src/@core/scss/template/_default-layout-w-vertical-nav.scss new file mode 100755 index 0000000..b5bb263 --- /dev/null +++ b/src/admin/src/@core/scss/template/_default-layout-w-vertical-nav.scss @@ -0,0 +1,28 @@ +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins"; + +$header: ".layout-navbar"; + +@if variables.$layout-vertical-nav-navbar-is-contained { + $header: ".layout-navbar .navbar-content-container"; +} + +.layout-wrapper.layout-nav-type-vertical { + // 👉 Layout footer + .layout-footer { + $ele-layout-footer: &; + + .footer-content-container { + // Sticky footer + @at-root { + // ℹ️ .layout-footer-sticky#{$ele-layout-footer} => .layout-footer-sticky.layout-wrapper.layout-nav-type-vertical .layout-footer + .layout-footer-sticky#{$ele-layout-footer} { + .footer-content-container { + box-shadow: 0 -4px 8px -4px rgba(var(--v-shadow-key-umbra-color), 42%); + padding-inline: 1.5rem; + } + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/_mixins.scss b/src/admin/src/@core/scss/template/_mixins.scss new file mode 100755 index 0000000..6f4a59a --- /dev/null +++ b/src/admin/src/@core/scss/template/_mixins.scss @@ -0,0 +1,12 @@ +@use "vuetify/lib/styles/settings" as vuetify_settings; + +@mixin avatar-font-sizes($map: $avatar-sizes) { + @each $sizeName, $multiplier in vuetify_settings.$size-scales { + /* stylelint-disable-next-line scss/no-global-function-names */ + $size: map-get($map, $sizeName); + + &.v-avatar--size-#{$sizeName} { + font-size: #{$size}px; + } + } +} diff --git a/src/admin/src/@core/scss/template/_utilities.scss b/src/admin/src/@core/scss/template/_utilities.scss new file mode 100755 index 0000000..c652d75 --- /dev/null +++ b/src/admin/src/@core/scss/template/_utilities.scss @@ -0,0 +1,51 @@ +.v-timeline{ + .v-timeline-item { + .app-timeline-title { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + font-size: 15px; + font-weight: 500; + letter-spacing: 0.15px; + line-height: 1.375rem; + } + + .app-timeline-meta { + color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)); + font-size: 13px; + letter-spacing: 0.4px; + line-height: 1.125rem; + } + + .app-timeline-text { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + font-size: .9375rem; + line-height: 1.375rem; + } + } +} + +.per-page-select { + margin-block: auto; + + .v-field__input { + align-items: center; + padding: 2px; + } + + .v-field__append-inner { + align-items: center; + padding: 0; + + .v-icon { + margin-inline-start: 0 !important; + } + } +} + +.leading-normal { + font-weight: 600; + letter-spacing: .0094rem; +} + +.bg-custom-background{ + background-color: rgb(var(--v-table-header-color)) !important; +} diff --git a/src/admin/src/@core/scss/template/_utils.scss b/src/admin/src/@core/scss/template/_utils.scss new file mode 100755 index 0000000..2969c21 --- /dev/null +++ b/src/admin/src/@core/scss/template/_utils.scss @@ -0,0 +1,41 @@ +@use "sass:string"; + +/* + ℹ️ This function is helpful when we have multi dimensional value + + Assume we have padding variable `$nav-padding-horizontal: 10px;` + With above variable let's say we use it in some style: + ```scss + .selector { + margin-left: $nav-padding-horizontal; + } + ``` + + Now, problem is we can also have value as `$nav-padding-horizontal: 10px 15px;` + In this case above style will be invalid. + + This function will extract the left most value from the variable value. + + $nav-padding-horizontal: 10px; => 10px; + $nav-padding-horizontal: 10px 15px; => 10px; + + This is safe: + ```scss + .selector { + margin-left: get-first-value($nav-padding-horizontal); + } + ``` +*/ +@function get-first-value($var) { + $start-at: string.index(#{$var}, " "); + + @if $start-at { + @return string.slice( + #{$var}, + 0, + $start-at + ); + } @else { + @return $var; + } +} diff --git a/src/admin/src/@core/scss/template/_variables.scss b/src/admin/src/@core/scss/template/_variables.scss new file mode 100755 index 0000000..d9b08f0 --- /dev/null +++ b/src/admin/src/@core/scss/template/_variables.scss @@ -0,0 +1,56 @@ +@use "sass:map"; +@use "utils"; + +$vertical-nav-horizontal-padding-custom: 1.4375rem 1rem; + +// ℹ️ We created this SCSS var to extract the start padding +// Docs: https://sass-lang.com/documentation/modules/string +// $vertical-nav-horizontal-padding => 0 8px; +// string.index(#{$vertical-nav-horizontal-padding}, " ") + 1 => 2 +// string.index(#{$vertical-nav-horizontal-padding}, " ") => 1 +// string.slice(0 8px, 2, -1) => 8px => $card-actions-padding-x + +$vertical-nav-horizontal-padding-start: utils.get-first-value($vertical-nav-horizontal-padding-custom) !default; +$vertical-nav-items-icon-margin-inline-end: 0 !default; + +@forward "@core/scss/base/variables" with ( + $layout-vertical-nav-collapsed-width: 68px !default, + // ℹ️ This is used to keep consistency between nav items and nav header left & right margin + // This is used by nav items & nav header + $vertical-nav-horizontal-spacing: 0 1rem !default, + $vertical-nav-horizontal-padding: $vertical-nav-horizontal-padding-custom !default, + // Vertical nav header padding + $vertical-nav-header-padding: 1.25rem 0 1.25rem $vertical-nav-horizontal-padding-start !default, + + // Vertical nav icons + $vertical-nav-items-icon-size: 1.375rem !default, + $vertical-nav-items-nested-icon-size: 0.75rem !default, + + + // Section title margin top (when its not first child) + $vertical-nav-section-title-mt: 1.25rem !default, + + $layout-vertical-nav-footer-height: 54px !default, + + // Horizontal nav icons + $horizontal-nav-items-icon-size: 1.375rem !default, + $horizontal-nav-items-icon-margin-inline-end: 0.5rem !default, + + // 👉 Horizontal nav + $horizontal-nav-padding: 0.625rem !default, + $horizontal-nav-third-level-icon-size: 0.75rem !default, + + // Gap between top level horizontal nav items + $horizontal-nav-top-level-items-gap: 8px !default, + + // ℹ️ This variable is used for horizontal nav popper content's `margin-top` and "The bridge"'s height. We need to sync both values. + $horizontal-nav-popper-content-top: calc(0.625rem + 0.375rem - 0.25rem) !default, + + $font-sizes: ( + "sm": 0.8125rem, + "base": 0.9375rem, + ), + $font-line-height: ( + "base": 1.375rem, + ), +); diff --git a/src/admin/src/@core/scss/template/_vertical-nav.scss b/src/admin/src/@core/scss/template/_vertical-nav.scss new file mode 100755 index 0000000..a126740 --- /dev/null +++ b/src/admin/src/@core/scss/template/_vertical-nav.scss @@ -0,0 +1,51 @@ +@use "@layouts/styles/mixins" as layoutsMixins; + +.layout-nav-type-vertical { + // 👉 Layout Vertical nav + .layout-vertical-nav { + .nav-items{ + padding-block-start: .25rem; + } + + // 👉 Vertical nav group + .nav-group { + .nav-group-arrow { + font-size: 1.375rem; + } + } + + // 👉 Nav group & Link + .nav-link, + .nav-group { + // shadow cut issue fix + margin-block-end: -0.5rem; + padding-block-end: 0.5rem; + + a { + outline: none; + } + } + + // 👉 Nav section title + .nav-section-title { + .placeholder-icon { + transform: translateX(-3px); + + @include layoutsMixins.rtl { + transform: translateX(3px); + } + } + } + + // 👉 Nav header + .nav-header { + padding-block: 1.25rem; + padding-inline: 23px 0; + } + } +} + +// 👉 Overlay +.layout-overlay{ + touch-action: none; +} diff --git a/src/admin/src/@core/scss/template/index.scss b/src/admin/src/@core/scss/template/index.scss new file mode 100755 index 0000000..23081c3 --- /dev/null +++ b/src/admin/src/@core/scss/template/index.scss @@ -0,0 +1,10 @@ +@use "sass:map"; +@use "@core/scss/base"; + +// layouts +@use "vertical-nav"; +@use "default-layout-w-vertical-nav"; + +// Utilities +@use "utilities"; + diff --git a/src/admin/src/@core/scss/template/libs/apex-chart.scss b/src/admin/src/@core/scss/template/libs/apex-chart.scss new file mode 100755 index 0000000..8f8fd66 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/apex-chart.scss @@ -0,0 +1,107 @@ +@use "@styles/variables/_vuetify.scss" as vuetify; +@use "@layouts/styles/mixins" as layoutsMixins; +@use "@core/scss/base/mixins"; + +body .apexcharts-canvas { + &line[stroke="transparent"] { + display: "none"; + } + + .apexcharts-tooltip { + @include mixins.elevation(3); + + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + background: rgb(var(--v-theme-surface)); + + .apexcharts-tooltip-title { + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + background: rgb(var(--v-theme-surface)); + font-weight: 600; + } + + &.apexcharts-theme-light { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + } + + &.apexcharts-theme-dark { + color: white; + } + + .apexcharts-tooltip-series-group:first-of-type { + padding-block-end: 0; + } + } + + .apexcharts-xaxistooltip { + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + background: rgb(var(--v-theme-grey-50)); + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + + &::after { + border-block-end-color: rgb(var(--v-theme-grey-50)); + } + + &::before { + border-block-end-color: rgba(var(--v-border-color), var(--v-border-opacity)); + } + } + + .apexcharts-yaxistooltip { + border-color: rgba(var(--v-border-color), var(--v-border-opacity)); + background: rgb(var(--v-theme-grey-50)); + + &::after { + border-inline-start-color: rgb(var(--v-theme-grey-50)); + } + + &::before { + border-inline-start-color: rgba(var(--v-border-color), var(--v-border-opacity)); + } + } + + .apexcharts-xaxistooltip-text, + .apexcharts-yaxistooltip-text { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + } + + .apexcharts-yaxis .apexcharts-yaxis-texts-g .apexcharts-yaxis-label { + @include layoutsMixins.rtl { + text-anchor: start; + } + } + + .apexcharts-text, + .apexcharts-tooltip-text, + .apexcharts-datalabel-label, + .apexcharts-datalabel, + .apexcharts-xaxistooltip-text, + .apexcharts-yaxistooltip-text, + .apexcharts-legend-text { + font-family: vuetify.$body-font-family !important; + } + + .apexcharts-pie-label { + fill: white; + filter: none; + } + + .apexcharts-marker { + box-shadow: none; + } + + .apexcharts-tooltip-marker { + margin-inline-end: 0.625rem; + + @include layoutsMixins.rtl { + margin-inline: 0 0.625rem !important; + } + } + + .apexcharts-legend-marker { + margin-inline-end: 0.3875rem !important; + + @include layoutsMixins.rtl { + margin-inline-end: 0.75rem !important; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/_overrides.scss b/src/admin/src/@core/scss/template/libs/vuetify/_overrides.scss new file mode 100755 index 0000000..95581fc --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/_overrides.scss @@ -0,0 +1,38 @@ +@use "@core/scss/base/utils"; +@use "@configured-variables" as variables; + +// 👉 Body +// set body font size 15px +body { + font-size: 15px !important; +} + +// 👉 Typography +.text-h1, +.text-h2, +.text-h3, +.text-h4, +.text-h5, +.text-h6, +.text-overline, +.v-input { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); +} + +.text-caption{ + color: rgba(var(--v-theme-on-background), var(--v-disabled-opacity)); +} + +.v-card-subtitle, +.text-subtitle-1, +.text-subtitle-2 { + color: rgba(var(--v-theme-on-background), 0.55); +} + +// 👉 Input placeholder alignment +.v-input--density-compact{ + input::placeholder { + position: relative; + inset-block-start: 1px; + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/_variables.scss b/src/admin/src/@core/scss/template/libs/vuetify/_variables.scss new file mode 100755 index 0000000..70bc70f --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/_variables.scss @@ -0,0 +1,323 @@ +$font-family-custom: "Inter Variable", sans-serif, -apple-system, blinkmacsystemfont, "Segoe UI", roboto, + "Helvetica Neue", arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +/* stylelint-disable length-zero-no-unit */ +@forward "../../../base/libs/vuetify/variables" with ( + $body-font-family: $font-family-custom !default, + $border-radius-root: 6px, + + $rounded: ( + "sm": 4px, + "shaped": 25px 0, + "lg":8px, + ) !default, + + // 👉 Typography + $typography: ( + "h1": ( + "size": 2.875rem, + "weight": 500, + "line-height": 4.25rem, + "letter-spacing": normal, + ), + "h2": ( + "size": 2.375rem, + "weight": 500, + "line-height": 3.5rem, + "letter-spacing": normal, + ), + "h3": ( + "size": 1.75rem, + "weight": 500, + "line-height": 2.625rem, + "letter-spacing": normal, + ), + "h4": ( + "size": 1.5rem, + "weight": 500, + "line-height": 2.375rem, + "letter-spacing": normal, + ), + "h5": ( + "size": 1.125rem, + "weight": 500, + "line-height": 1.75rem, + "letter-spacing": normal, + ), + "h6": ( + "size": 0.9375rem, + "line-height": 1.375rem, + "letter-spacing": normal, + ), + "subtitle-1": ( + "size": 0.9375rem, + "line-height": 1.375rem, + "letter-spacing": normal, + ), + "subtitle-2": ( + "size": 0.8125rem, + "line-height": 1.25rem, + "letter-spacing": normal, + ), + "body-1": ( + "size": 0.9375rem, + "line-height": 1.375rem, + "letter-spacing": normal, + ), + "body-2": ( + "size": 0.8125rem, + "line-height": 1.25rem, + "letter-spacing": normal, + ), + "caption": ( + "size": 0.8125rem, + "line-height": 1.125rem, + "letter-spacing": 0.025rem, + ), + "overline": ( + "weight": 400, + "line-height": 0.875rem, + "letter-spacing": 0.05rem, + ), + "button": ( + "size": 0.9375rem, + "weight": 500, + "letter-spacing": normal, + "font-family": $font-family-custom, + "text-transform": capitalize, + ), + )!default, + + // 👉 Shadows + $shadow-key-umbra: ( + 0: (0 0 0 0 rgba(var(--v-shadow-key-umbra-color), 1)), + 1: (0 2px 4px rgba(var(--v-shadow-key-umbra-color), 0.12)), + 2: (0 2px 4px 0 rgba(var(--v-shadow-key-umbra-color), var(--v-shadow-xs-opacity))), + 3: (0 3px 8px rgba(var(--v-shadow-key-umbra-color), 0.14)), + 4: (0 3px 6px 0 rgba(var(--v-shadow-key-umbra-color), var(--v-shadow-sm-opacity))), + 5: (0 4px 10px rgba(var(--v-shadow-key-umbra-color), 0.15)), + 6: (0 4px 10px 0 rgba(var(--v-shadow-key-umbra-color), var(--v-shadow-md-opacity))), + 7: (0 4px 18px rgba(var(--v-shadow-key-umbra-color), 0.1)), + 8: (0 6px 16px 0 rgba(var(--v-shadow-key-umbra-color), var(--v-shadow-lg-opacity))), + 9: (0 5px 14px rgba(var(--v-shadow-key-umbra-color), 0.18)), + 10: (0 8px 28px 0 rgba(var(--v-shadow-key-umbra-color), var(--v-shadow-xl-opacity))), + 11: (0 5px 16px rgba(var(--v-shadow-key-umbra-color), 0.2)), + 12: (0 6px 17px rgba(var(--v-shadow-key-umbra-color), 0.22)), + 13: (0 6px 18px rgba(var(--v-shadow-key-umbra-color), 0.22)), + 14: (0 6px 19px rgba(var(--v-shadow-key-umbra-color), 0.24)), + 15: (0 7px 20px rgba(var(--v-shadow-key-umbra-color), 0.24)), + 16: (0 7px 21px rgba(var(--v-shadow-key-umbra-color), 0.26)), + 17: (0 7px 22px rgba(var(--v-shadow-key-umbra-color), 0.26)), + 18: (0 8px 23px rgba(var(--v-shadow-key-umbra-color), 0.28)), + 19: (0 8px 24px 6px rgba(var(--v-shadow-key-umbra-color), 0.28)), + 20: (0 9px 25px rgba(var(--v-shadow-key-umbra-color), 0.3)), + 21: (0 9px 26px rgba(var(--v-shadow-key-umbra-color), 0.32)), + 22: (0 9px 27px rgba(var(--v-shadow-key-umbra-color), 0.32)), + 23: (0 10px 28px rgba(var(--v-shadow-key-umbra-color), 0.34)), + 24: (0 10px 30px rgba(var(--v-shadow-key-umbra-color), 0.34)) + ) !default, + + $shadow-key-penumbra: ( + 0: (0 0 transparent), + 1: (0 0 transparent), + 2: (0 0 transparent), + 3: (0 0 transparent), + 4: (0 0 transparent), + 5: (0 0 transparent), + 6: (0 0 transparent), + 7: (0 0 transparent), + 8: (0 0 transparent), + 9: (0 0 transparent), + 10: (0 0 transparent), + 11: (0 0 transparent), + 12: (0 0 transparent), + 13: (0 0 transparent), + 14: (0 0 transparent), + 15: (0 0 transparent), + 16: (0 0 transparent), + 17: (0 0 transparent), + 18: (0 0 transparent), + 19: (0 0 transparent), + 20: (0 0 transparent), + 21: (0 0 transparent), + 22: (0 0 transparent), + 23: (0 0 transparent), + 24: (0 0 transparent), + ) !default, + + $shadow-key-ambient: ( + 0: (0 0 transparent), + 1: (0 0 transparent), + 2: (0 0 transparent), + 3: (0 0 transparent), + 4: (0 0 transparent), + 5: (0 0 transparent), + 6: (0 0 transparent), + 7: (0 0 transparent), + 8: (0 0 transparent), + 9: (0 0 transparent), + 10: (0 0 transparent), + 11: (0 0 transparent), + 12: (0 0 transparent), + 13: (0 0 transparent), + 14: (0 0 transparent), + 15: (0 0 transparent), + 16: (0 0 transparent), + 17: (0 0 transparent), + 18: (0 0 transparent), + 19: (0 0 transparent), + 20: (0 0 transparent), + 21: (0 0 transparent), + 22: (0 0 transparent), + 23: (0 0 transparent), + 24: (0 0 transparent), + ) !default, + + // 👉 Avatar + $avatar-color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)) !default, + + // 👉 Alert + $alert-title-font-size: 1.125rem !default, + $alert-text-line-height: 1.625rem !default, + + // 👉 Autocomplete + $autocomplete-content-elevation: 8 !default, + $combobox-content-elevation: 8 !default, + $select-content-elevation: 8 !default, + + // 👉 Badge + $badge-height: 1.375rem !default, + $badge-min-width: 1.375rem !default, + $badge-dot-height: 8px !default, + $badge-dot-width: 8px !default, + $badge-border-radius: 50px !default, + $badge-font-size: 0.8125rem !default, + + // 👉 Buttons + $button-height: 38px !default, + $button-padding-ratio: 2.15 !default, + $button-margin-start: 0 !default, + $button-disabled-opacity: .45 !default, + $button-elevation: ('default': 2, 'hover': 2, 'active': 0) !default, + $button-density: ('default': 0, 'comfortable': -1, 'compact': -2) !default, + $button-line-height: 1.375rem !default, + $button-margin-end: 0.375rem !default, + $button-card-actions-padding: 0 18px !default, + + // 👉 Chip + $chip-font-size: 13px !default, + $chip-close-size: 20px !default, + $chip-font-weight: 500 !default, + + // 👉 Cards + $card-actions-padding: 0 6px 6px !default, + $card-title-font-size: 1.125rem !default, + $card-title-line-height: 1.75rem !default, + $card-text-font-size: 0.9375rem !default, + $card-text-line-height: 1.375rem !default, + $card-subtitle-font-size: 0.9375rem !default, + $card-subtitle-line-height: 1.375rem !default, + $card-subtitle-font-weight: 400 !default, + $card-subtitle-header-padding: 0 !default, + + // 👉 Dialog + $dialog-elevation: 10 !default, + $dialog-card-header-padding: 20px !default, + $dialog-card-text-padding: 0 20px 20px !default, + + // 👉 Expansion Panel + $expansion-panel-active-margin: 0.5rem !default, + $expansion-panel-text-padding: 0 20px 20px !default, + $expansion-panel-title-padding: 12px 20px !default, + $expansion-panel-title-min-height: 46px !default, + $expansion-panel-active-title-min-height: 46px !default, + + // 👉 Field + $field-outline-opacity: 0.22 !default, + $field-control-affixed-padding: 16px !default, + $field-control-affixed-inner-padding: 10px !default, + $field-font-size: 15px !default, + + // 👉 Label + $label-font-size: 0.9375rem !default, + $label-letter-spacing: normal !default, + + // 👉 List + $list-item-one-line-min-height: 38px !default, + $list-subheader-min-height: 38px !default, + $list-item-padding: 8px 20px !default, + $list-subheader-font-weight: 500 !default, + $list-item-icon-margin-start: 12px !default, + $list-item-min-height: 38px !default, + $list-item-nav-title-font-size: 0.9375rem !default, + $list-item-nav-title-font-weight: 400 !default, + $list-item-nav-subtitle-font-size: 0.8125rem !default, + $list-item-subtitle-line-height: 1.25rem !default, + + // 👉 label + $field-label-floating-scale: 0.8125 !default, + + // 👉 Snackbar + $snackbar-background: rgb(var(--v-tooltip-background)) !default, + $snackbar-color: rgb(var(--v-theme-surface)) !default, + $snackbar-content-padding: 12px 16px !default, + $snackbar-wrapper-padding: 0 !default, + $snackbar-wrapper-min-height: 44px !default, + $snackbar-elevation: 2 !default, + $snackbar-btn-padding: 0 10px !default, + $snackbar-action-margin: 16px !default, + + // 👉 Slider + $slider-thumb-hover-opacity: var(--v-activated-opacity) !default, + + // 👉 Switch + $switch-inset-track-width: 1.875rem !default, + $switch-inset-track-height: 1.125rem !default, + $switch-inset-thumb-height: 0.875rem !default, + $switch-inset-thumb-width: 0.875rem !default, + $switch-inset-thumb-off-height: 0.875rem !default, + $switch-track-opacity: 1 !default, + $switch-track-background: rgba(var(--v-theme-on-surface), var(--v-focus-opacity)) !default, + + // 👉 Tooltip + $tooltip-background-color: rgb(var(--v-tooltip-background)) !default, + $tooltip-text-color: rgb(var(--v-theme-surface)) !default, + $tooltip-border-radius: 0.25rem !default, + $tooltip-font-size: 0.8125rem !default, + $tooltip-padding: 4px 12px !default, + $tooltip-line-height: 1.25rem !default, + + // 👉 VPagination + $pagination-item-margin: 0.1875rem !default, + + // 👉 Tabs + $tabs-height: 38px !default, + $tab-min-width: 60px !default, + + // 👉 Timeline + $timeline-divider-line-background: rgba(var(--v-border-color), var(--v-border-opacity)) !default, + $timeline-divider-line-thickness: 1.5px !default, + $timeline-item-padding: 16px !default, + + // 👉 Slider + $slider-track-active-size-offset: 0px !default, + $slider-thumb-label-border-radius: 6px !default, + $slider-thumb-label-height: 28px !default, + $slider-thumb-label-padding: 4px 10px !default, + + // 👉 Table + $table-row-height: 50px !default, + $table-header-font-weight: 500 !default, + $table-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default, + $table-font-size: 15px !default, + $table-column-padding: 0 20px !default, + + // 👉 Radio + $radio-group-label-selection-group-padding-inline: 0 !default, + + // 👉 navigation drawer + $navigation-drawer-temporary-elevation: 8 !default, + $navigation-drawer-transition-duration: 0.4s !default, + + // 👉 Messages + $messages-font-size: 13px !default, +); diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_alert.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_alert.scss new file mode 100755 index 0000000..a2a9cf5 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_alert.scss @@ -0,0 +1,103 @@ +@use "@core/scss/base/mixins"; +@use "@configured-variables" as variables; + +/* 👉 Alert +/ ℹ️ custom icon styling */ + +// 👉 Alert +.v-alert { + .v-alert__content { + font-size: 0.9375rem; + font-weight: 400; + line-height: 1.375rem; + + .v-alert-title { + margin-block-end: 0.25rem; + } + } + + &:not(.v-alert--prominent) .v-alert__prepend { + border-radius: 0.375rem; + block-size: 1.875rem; + inline-size: 1.875rem; + + .v-icon { + margin: auto; + block-size: 1.375rem !important; + font-size: 1.375rem !important; + inline-size: 1.375rem !important; + } + } + + &:not(.v-alert--prominent) { + &.v-alert--variant-flat, + &.v-alert--variant-elevated { + .v-alert__prepend { + background-color: #fff; + + @include mixins.elevation(2); + } + } + + &.v-alert--variant-tonal { + .v-alert__prepend { + z-index: 1; + } + } + } + + .v-alert__close { + .v-btn--icon { + --v-btn-height: 34px; + + .v-btn__content { + padding: 0.375rem; + + .v-icon { + block-size: 1.25rem; + font-size: 1.25rem; + inline-size: 1.25rem; + } + } + } + } +} + +@each $color-name in variables.$theme-colors-name { + .v-alert { + &:not(.v-alert--prominent) { + &.bg-#{$color-name}, + &.text-#{$color-name} { + .v-alert__prepend .v-icon { + color: rgb(var(--v-theme-#{$color-name})) !important; + } + } + + &.v-alert--variant-tonal { + &.text-#{$color-name}, + &.bg-#{$color-name} { + .v-alert__underlay { + background: rgb(var(--v-theme-#{$color-name})) !important; + } + + .v-alert__prepend { + background-color: rgb(var(--v-theme-#{$color-name})); + + .v-icon { + color: #fff !important; + } + } + } + } + + &.v-alert--variant-outlined { + &.text-#{$color-name}, + &.bg-#{$color-name} { + .v-alert__prepend { + background-color: rgba(var(--v-theme-#{$color-name}), 0.16); + } + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_avatar.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_avatar.scss new file mode 100755 index 0000000..c5215b6 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_avatar.scss @@ -0,0 +1,28 @@ +@use "@core/scss/base/mixins"; + +// 👉 Avatar +body { + .v-avatar { + font-size: 0.9375rem; + + .v-icon { + block-size: 1.5rem; + font-size: 1.5rem; + inline-size: 1.5rem; + } + + &.v-avatar--variant-tonal:not([class*="text-"]) { + .v-avatar__underlay { + --v-activated-opacity: 0.08; + } + } + } + + .v-avatar-group { + > * { + &:hover { + @include mixins.elevation(6); + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_badge.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_badge.scss new file mode 100755 index 0000000..bfae585 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_badge.scss @@ -0,0 +1,35 @@ +@use "@configured-variables" as variables; + +// 👉 Badge +.v-badge { + &.v-badge--inline:not(.v-badge--dot) { + .v-badge__wrapper { + .v-badge__badge { + padding-block: 4px; + padding-inline: 8px; + } + } + } + + &.v-badge--tonal { + @each $color-name in variables.$theme-colors-name { + .v-badge__wrapper { + .v-badge__badge.bg-#{$color-name} { + background-color: rgba(var(--v-theme-#{$color-name}), var(--v-activated-opacity)) !important; + color: rgb(var(--v-theme-#{$color-name})) !important; + } + } + } + } + + /* stylelint-disable-next-line no-descending-specificity */ + &.v-badge--bordered.v-badge--dot .v-badge__badge { + border-radius: 10px; + block-size: 12px; + inline-size: 12px; + + &::after { + border-width: 2px; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_button.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_button.scss new file mode 100755 index 0000000..5f4e799 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_button.scss @@ -0,0 +1,271 @@ +/* stylelint-disable no-descending-specificity */ +@use "sass:list"; +@use "sass:map"; +@use "@configured-variables" as variables; + +/* 👉 Button + Above map but opacity values as key and variant as value */ + +body { + .v-btn { + &:not(.v-btn--block) { + min-inline-size: auto; + } + + &--variant-elevated, + &--variant-flat { + &.v-btn--disabled { + .v-btn__overlay { + opacity: 0.45; + } + } + } + + // Default (elevated) button + /* stylelint-disable-next-line no-duplicate-selectors */ + &--variant-elevated, + &--variant-flat { + // We want darker background on hover instead of light + + &:hover { + .v-btn__overlay { + opacity: 0; + } + } + + &:not(.v-btn--loading, .v-btn--disabled) { + @each $color-name in variables.$theme-colors-name { + &.bg-#{$color-name} { + &:hover, + &:active, + &:focus { + background-color: rgb(var(--v-theme-#{$color-name}-darken-1)) !important; + } + } + } + } + } + + &--variant-elevated { + &:active { + box-shadow: none; + } + } + + // Outlined variant + &--variant-outlined, + &--variant-text { + .v-btn__overlay { + --v-hover-opacity: 0.08; + } + + &:active { + .v-btn__overlay { + opacity: var(--v-hover-opacity); + } + } + + &:focus { + .v-btn__overlay { + opacity: var(--v-hover-opacity); + } + } + } + + // Tonal variant + &--variant-tonal { + &:hover { + .v-btn__underlay { + opacity: 0; + } + + .v-btn__overlay { + --v-hover-opacity: 0.24; + } + } + + &:active { + .v-btn__overlay { + --v-hover-opacity: 0.24; + + opacity: var(--v-hover-opacity); + } + + .v-btn__underlay { + opacity: 0; + } + } + + &:focus { + .v-btn__overlay { + --v-hover-opacity: 0.24; + + opacity: var(--v-hover-opacity); + } + + .v-btn__underlay { + opacity: 0; + } + } + } + + &--icon.v-btn--density-default { + block-size: var(--v-btn-height); + inline-size: var(--v-btn-height); + padding-inline: 6px; + + &.v-btn--size-default { + .v-icon { + --v-icon-size-multiplier: 1 !important; + } + } + + &.v-btn--size-small { + .v-icon { + block-size: 20px; + font-size: 20px; + inline-size: 20px; + } + } + + &.v-btn--size-large { + .v-icon { + block-size: 28px; + font-size: 28px; + inline-size: 28px; + } + } + } + + &:not(.v-btn--icon) .v-icon { + --v-icon-size-multiplier: 0.7115; + + inline-size: auto; + } + + &--variant-text, + &--variant-plain { + &:not(.v-btn--icon) { + padding-inline: 14px; + } + } + + // Button Size + &--size-x-small { + --v-btn-height: 28px; + --v-btn-size: 11px; + + &:not(.v-btn--icon) { + border-radius: 0.125rem; + } + + line-height: 14px; + padding-block: 0; + padding-inline: 10px; + } + + &--size-small { + --v-btn-height: 34px; + --v-btn-size: 13px; + + &:not(.v-btn--icon) { + border-radius: 0.25rem; + } + + line-height: 18px; + padding-block: 0; + padding-inline: 14px; + + .v-icon { + --v-icon-size-multiplier: 0.718; + } + } + + &--size-large { + --v-btn-height: 42px; + --v-btn-size: 17px; + + &:not(.v-btn--icon) { + border-radius: 0.5rem; + } + + line-height: 26px; + padding-block: 0; + padding-inline: 22px; + } + + &--size-x-large { + --v-btn-height: 48px; + --v-btn-size: 19px; + + &:not(.v-btn--icon) { + border-radius: 0.625rem; + } + + line-height: 30px; + padding-block: 0; + padding-inline: 26px; + } + + // Toggle Button + &-toggle { + .v-btn { + border-radius: 0.375rem; + block-size: 52px !important; + border-inline-end: none; + inline-size: 52px !important; + + &.v-btn--density-comfortable { + block-size: 44px !important; + inline-size: 44px !important; + } + + &.v-btn--density-compact { + block-size: 36px !important; + inline-size: 36px !important; + } + + .v-icon { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + font-size: 24px; + } + + &--active { + .v-icon { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + } + } + } + + &.v-btn-group { + align-items: center; + padding: 7px; + border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + block-size: 66px; + + .v-btn.v-btn--active { + .v-btn__overlay { + --v-activated-opacity: 0.08; + } + } + + &.v-btn-group--density-compact { + block-size: 50px; + } + + &.v-btn-group--density-comfortable { + block-size: 58px; + } + } + } + } + + // 👉 Btn group + .v-btn-group { + border: none; + + &.v-btn-group--divided .v-btn:not(:last-child) { + border-inline-end-color: unset; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_cards.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_cards.scss new file mode 100755 index 0000000..3302d3e --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_cards.scss @@ -0,0 +1 @@ +// 👉 Card diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_checkbox.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_checkbox.scss new file mode 100755 index 0000000..d36adc9 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_checkbox.scss @@ -0,0 +1,42 @@ +@use "sass:list"; +@use "sass:map"; +@use "@styles/variables/vuetify"; +@use "@configured-variables" as variables; + +// 👉 checkbox box shadow +.v-checkbox-btn { + &.v-selection-control--dirty { + .v-selection-control__input { + .v-icon.custom-checkbox-checked, + .v-icon.custom-checkbox-indeterminate { + // ℹ️ Using filter: drop-shadow() instead of box-shadow because box-shadow creates white background for SVG;Usingfilter + filter: drop-shadow(rgba(var(--v-shadow-key-umbra-color), 16%) 0 2px 4px); + } + } + } + + &.v-selection-control { + .v-label { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + } + + .v-selection-control__input { + svg { + font-size: 1.5rem; + } + } + } + + &:not(.v-selection-control--dirty) { + .v-selection-control__input { + > .v-icon { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + opacity: 1; + } + + > .custom-checkbox-indeterminate { + color: rgb(var(--v-theme-primary)); + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_chip.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_chip.scss new file mode 100755 index 0000000..f702f35 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_chip.scss @@ -0,0 +1,99 @@ +// 👉 Chip +.v-chip { + line-height: 1.25rem !important; + + &:not(.v-chip--variant-elevated) { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + } + + .v-chip__close { + margin-inline: 4px -8px !important; + + .v-icon { + opacity: 0.7; + } + } + + &:not([class*="text-"]) { + --v-activated-opacity: 0.08; + } + + &.v-chip--size-small { + --v-chip-height: 24px !important; + + font-size: 13px !important; + padding-block: 0 !important; + padding-inline: 12px !important; + + .v-chip__prepend { + .v-icon--start { + font-size: 1rem; + margin-inline: -8px 4px; + } + + .v-avatar { + --v-avatar-height: 16px; + } + + .v-avatar--start { + margin-inline: -8px 4px; + } + } + + .v-chip__append { + .v-icon--end { + font-size: 1rem; + margin-inline: 4px -8px; + } + + .v-avatar { + --v-avatar-height: 16px; + } + + .v-avatar--end { + margin-inline: 4px -8px; + } + } + + .v-chip__close { + font-size: 16px; + max-block-size: 16px; + max-inline-size: 16px; + } + } + + &.v-chip--size-default { + padding-block: 0 !important; + padding-inline: 16px !important; + + .v-chip__prepend { + .v-icon--start { + font-size: 1.25rem; + margin-inline: -8px 4px; + } + + .v-avatar { + --v-avatar-height: 20px; + } + + .v-avatar--start { + margin-inline: -8px 4px; + } + } + + .v-chip__append { + .v-icon--end { + font-size: 1.25rem; + margin-inline: 4px -8px; + } + + .v-avatar { + --v-avatar-height: 20px; + } + + .v-avatar--end { + margin-inline: 4px -8px; + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_dialog.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_dialog.scss new file mode 100755 index 0000000..f5b36e7 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_dialog.scss @@ -0,0 +1,12 @@ +// 👉 Dialog + +body { + .v-dialog { + font-size: 0.9375rem; + line-height: 1.375rem; + + .v-dialog-close-btn { + color: rgb(var(--v-theme-secondary)) !important; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_expansion-panels.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_expansion-panels.scss new file mode 100755 index 0000000..e4fcab4 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_expansion-panels.scss @@ -0,0 +1,47 @@ +@use "@core/scss/base/mixins"; + +// 👉 Expansion Panel +.v-expansion-panels { + .v-expansion-panel { + .v-expansion-panel-title { + font-weight: 500; + + &--active { + .v-expansion-panel-title__overlay, + &:hover .v-expansion-panel-title__overlay { + opacity: 0 !important; + } + } + + .v-expansion-panel-title__icon { + .v-icon { + block-size: 1.25rem; + font-size: 1.25rem; + inline-size: 1.25rem; + } + } + + &:hover { + .v-expansion-panel-title__overlay { + opacity: 0 !important; + } + } + } + + .v-expansion-panel-text { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + font-size: 15px; + line-height: 1.375rem; + } + } + + &:not(.v-expansion-panels--variant-accordion) { + .v-expansion-panel { + &.v-expansion-panel--active { + .v-expansion-panel__shadow { + @include mixins.elevation(6); + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_field.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_field.scss new file mode 100755 index 0000000..97ca93e --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_field.scss @@ -0,0 +1,58 @@ +@use "@configured-variables" as variables; +@use "sass:map"; +@use "@styles/variables/vuetify"; +@use "@core/scss/base/mixins"; +@use "@core/scss/base/utils"; + +// 👉 VField +// Override Vuetify's default outline color for text fields to match the theme +// ℹ️ We cannot override directly border color because it does not work with dirty or focus state +.v-field__outline { + color: rgba(var(--v-theme-on-surface)); + + &:not([class*="text-"]) .v-label { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + } +} + +// override input height on comfortable and compact density +.v-text-field, +.v-autocomplete, +.v-combobox, +.v-file-input, +.v-select { + &.v-input.v-input--density-default:not(.v-textarea) .v-field__input { + min-block-size: 56px; + } + + &.v-input.v-input--density-comfortable:not(.v-textarea) .v-field__input { + min-block-size: 48px; + } + + &.v-input.v-input--density-compact:not(.v-textarea) .v-field__input { + min-block-size: 40px; + } +} + +.v-field.v-field--focused .v-field__outline, +.v-input.v-input--error .v-field__outline { + --v-field-border-opacity: 1 !important; +} + +// hover state outline color +@media (hover: hover) { + .v-field:not(.v-field--focused, .v-field--error):hover .v-field__outline { + --v-field-border-opacity: 0.6 !important; + } +} + +.v-field__prepend-inner, +.v-field__append-inner, +.v-field__clearable, +.v-input__prepend, +.v-input__append { + > .v-icon { + font-size: 20px; + opacity: var(--v-high-emphasis-opacity) !important; + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_list.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_list.scss new file mode 100755 index 0000000..e5548e9 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_list.scss @@ -0,0 +1,22 @@ +// 👉 VList + +.v-list { + // .v-icon { + // font-size: 1.375rem;font-sizefont-size + // } + + .v-list-item { + &.v-list-item--active:not(.v-list-group__header) { + .v-list-item__content, + .v-list-item__prepend { + * { + color: rgb(var(--v-theme-primary)); + } + } + + .v-list-item__overlay { + background: rgb(var(--v-theme-primary)); + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_menu.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_menu.scss new file mode 100755 index 0000000..a6b27ad --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_menu.scss @@ -0,0 +1,6 @@ +// 👉 VMenu +.v-menu { + .v-list-item--density-default:not(.v-list-item--nav).v-list-item--one-line { + padding-inline: 16px; + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_otp-input.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_otp-input.scss new file mode 100755 index 0000000..781498d --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_otp-input.scss @@ -0,0 +1,18 @@ +// 👉 Otp input + +.v-otp-input { + justify-content: unset !important; + + .v-otp-input__content { + max-inline-size: 100%; + + .v-field.v-field--focused { + .v-field__outline { + .v-field__outline__start, + .v-field__outline__end { + border-color: rgb(var(--v-theme-primary)) !important; + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_pagination.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_pagination.scss new file mode 100755 index 0000000..e129dc3 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_pagination.scss @@ -0,0 +1,172 @@ +/* stylelint-disable no-descending-specificity */ +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins"; + +// 👉 VPagination + +.v-pagination { + .v-pagination__list { + .v-pagination__next, + .v-pagination__last, + .v-pagination__first, + .v-pagination__prev { + .v-btn { + &.v-btn--icon { + &.v-btn--size-default { + .v-icon { + block-size: 1.375rem; + font-size: 1.375rem; + inline-size: 1.375rem; + } + } + + &.v-btn--size-small { + .v-icon { + block-size: 1.25rem; + font-size: 1.25rem; + inline-size: 1.25rem; + } + } + + &.v-btn--size-large { + .v-icon { + block-size: 1.5rem; + font-size: 1.5rem; + inline-size: 1.5rem; + } + } + } + } + } + + // Common styles for buttons + .v-pagination__item, + .v-pagination__next, + .v-pagination__last, + .v-pagination__first, + .v-pagination__prev { + .v-btn { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + font-weight: 400; + line-height: 1; + transform: none; + + &--size-default { + --v-btn-size: 13px; + } + + &--size-large { + --v-btn-size: 15px; + } + + &.v-btn--disabled { + opacity: 0.4; + } + + &--variant-tonal { + .v-btn__underlay { + --v-activated-opacity: 0.08; + } + + &:hover { + .v-btn__underlay { + --v-activated-opacity: 0; + } + + .v-btn__overlay { + --v-hover-opacity: 0.16; + } + } + } + + @each $color-name in variables.$theme-colors-name { + &--variant-tonal.text-#{$color-name} { + .v-btn__underlay { + background: rgb(var(--v-theme-on-surface)); + } + + .v-btn__content { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + } + + &:hover { + .v-btn__content { + color: rgb(var(--v-theme-#{$color-name})); + } + } + } + } + + &--variant-outlined { + &:hover { + .v-btn__overlay { + --v-hover-opacity: 0.06; + } + } + } + } + } + + .v-pagination__item--is-active { + .v-btn { + &:not([class*="text-"]) { + color: rgb(var(--v-theme-primary)); + } + } + + .v-btn.v-btn--variant-tonal { + .v-btn__overlay { + --v-hover-opacity: 0.16; + + background: rgb(var(--v-theme-primary)); + opacity: var(--v-hover-opacity); + } + + .v-btn__content { + color: rgb(var(--v-theme-primary)); + } + + .v-btn__underlay { + opacity: 0; + } + + &:hover { + .v-btn__overlay { + --v-hover-opacity: 0.24; + } + } + } + + @each $color-name in variables.$theme-colors-name { + .v-btn.v-btn--variant-tonal.text-#{$color-name} { + @include mixins.elevation(2); + + .v-btn__overlay { + background: rgb(var(--v-theme-#{$color-name})); + opacity: 1; + } + + .v-btn__content { + z-index: 1; + color: #fff; + } + } + } + + .v-btn.v-btn--variant-outlined { + border-color: rgb(var(--v-theme-primary)); + + .v-btn__content { + color: rgb(var(--v-theme-primary)); + } + + .v-btn__overlay { + --v-hover-opacity: 0.16; + + background: rgb(var(--v-theme-primary)); + opacity: var(--v-hover-opacity); + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_progress.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_progress.scss new file mode 100755 index 0000000..c55b2de --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_progress.scss @@ -0,0 +1,3 @@ +@use "@configured-variables" as variables; + +// 👉 Progress diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_radio.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_radio.scss new file mode 100755 index 0000000..ced4200 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_radio.scss @@ -0,0 +1,47 @@ +@use "@core/scss/base/mixins"; +@use "@configured-variables" as variables; + +// 👉 Radio +.v-radio, +.v-radio-btn { + &.v-selection-control--dirty { + .v-selection-control__input { + .custom-radio-checked { + filter: drop-shadow(rgba(var(--v-shadow-key-umbra-color), 16%) 0 2px 4px); + } + } + } + + &.v-selection-control { + .v-selection-control__input { + svg { + font-size: 1.5rem; + } + } + + .v-label { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + } + } + + &:not(.v-selection-control--dirty) { + .v-selection-control__input > .v-icon { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + opacity: 1; + } + } +} + +.v-radio-group.v-input > .v-input__control > .v-label { + font-size: 0.9375rem; + line-height: 22px; + margin-inline-start: 0; +} + +.v-radio-group { + .v-selection-control-group { + .v-radio:not(:last-child) { + margin-inline-end: 0; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_rating.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_rating.scss new file mode 100755 index 0000000..7e32287 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_rating.scss @@ -0,0 +1,14 @@ +// // 👉 Rating +// .v-rating { +// .v-rating__wrapper { +// .v-btn { +// &:hover { +// transform: none;transform +// } + +// .v-icon { +// --v-icon-size-multiplier: 1;--v-icon-size-multiplier +// } +// } +// } +// } diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_slider.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_slider.scss new file mode 100755 index 0000000..24ae833 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_slider.scss @@ -0,0 +1,28 @@ +// 👉 Slider + +.v-slider { + .v-slider-track__background--opacity { + opacity: 0.16; + } +} + +.v-slider-thumb { + .v-slider-thumb__surface::after { + border-radius: 50%; + background-color: #fff; + block-size: calc(var(--v-slider-thumb-size) - 10px); + inline-size: calc(var(--v-slider-thumb-size) - 10px); + } + + .v-slider-thumb__label { + background-color: rgb(var(--v-tooltip-background)); + color: rgb(var(--v-theme-surface)); + font-weight: 500; + letter-spacing: 0.15px; + line-height: 1.25rem; + + &::before { + content: none; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_snackbar.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_snackbar.scss new file mode 100755 index 0000000..f56987a --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_snackbar.scss @@ -0,0 +1,10 @@ +// 👉 snackbar + +.v-snackbar { + .v-snackbar__actions { + .v-btn { + padding-block: 0; + padding-inline: 10px; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_switch.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_switch.scss new file mode 100755 index 0000000..d84ab3c --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_switch.scss @@ -0,0 +1,57 @@ +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins"; + +// 👉 Switch + +.v-switch { + .v-label { + color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity)); + line-height: 22px; + } +} + +.v-switch.v-switch--inset { + .v-selection-control .v-selection-control__wrapper { + block-size: 36px; + } + + .v-ripple__container { + opacity: 0; + } + + .v-switch__track { + background-color: rgba(var(--v-theme-on-surface), var(--v-focus-opacity)); + box-shadow: 0 0 4px 0 rgba(0, 0, 0, 16%) inset; + opacity: 1; + } + + .v-selection-control__input { + transform: translateX(-5px) !important; + + --v-selection-control-size: 1.125rem; + + .v-switch__thumb { + background-color: #fff; + block-size: 0.875rem; + box-shadow: none; + filter: drop-shadow(0 2px 4px rgba(var(--v-shadow-key-umbra-color), 16%)); + inline-size: 0.875rem; + transform: scale(1); + } + } + + .v-selection-control--dirty { + @each $color-name in variables.$theme-colors-name { + .text-#{$color-name} { + .v-switch__track { + border-color: rgb(var(--v-theme-#{$color-name})); + background-color: rgb(var(--v-theme-#{$color-name})); + } + } + } + + .v-selection-control__input { + transform: translateX(5px) !important; + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_table.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_table.scss new file mode 100755 index 0000000..30f8e94 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_table.scss @@ -0,0 +1,36 @@ +.v-data-table { + table { + tbody { + tr { + &.v-data-table-group-header-row { + td { + background: none; + } + } + } + } + } +} + +// 👉 Table +.v-table { + .v-table__wrapper { + border-radius: 0; + + table { + thead { + tr { + th { + background: rgb(var(--v-table-header-color)) !important; + border-block-end: none !important; + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)) !important; + font-size: 0.8125rem; + letter-spacing: 0.2px; + line-height: 24px; + text-transform: uppercase; + } + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_tabs.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_tabs.scss new file mode 100755 index 0000000..32fadd5 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_tabs.scss @@ -0,0 +1,113 @@ +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins"; + +body { + .v-tabs { + .v-tab.v-btn { + color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity)); + padding-block: 0; + padding-inline: 1.375rem; + + .v-icon { + block-size: 1.125rem; + font-size: 1.125rem; + inline-size: 1.125rem; + } + + &.v-btn--stacked { + .v-icon { + block-size: 1.5rem !important; + font-size: 1.5rem !important; + inline-size: 1.5rem !important; + } + } + } + + &:not(.v-tabs-pill) { + &.v-tabs--vertical { + border-inline-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + + .v-tab__slider { + inset-inline-end: 0; + inset-inline-start: unset; + } + } + + &.v-tabs--horizontal { + border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + + .v-tab__slider { + inset-block-end: 1px; + inset-block-start: unset; + } + } + + .v-tab { + &.v-tab--selected { + &.v-btn.v-btn--variant-text { + &:hover, + &:active, + &:focus { + .v-btn__overlay { + --v-hover-opacity: 0; + } + } + } + } + + &:not(.v-tab--selected) { + &.v-btn.v-btn--variant-text { + &:hover, + &:active, + &:focus { + color: rgb(var(--v-theme-primary)); + + .v-btn__overlay { + --v-hover-opacity: 0; + } + + .v-btn__content { + .v-tab__slider { + opacity: var(--v-activated-opacity); + } + } + } + } + } + } + } + + &.v-tabs-pill { + .v-slide-group__content { + gap: 0.25rem; + } + + &.v-slide-group, + .v-slide-group__container { + box-sizing: content-box; + padding: 1rem; + margin: -1rem; + } + + /* stylelint-disable-next-line no-descending-specificity */ + .v-tab { + &.v-btn { + border-radius: 0.375rem !important; + } + + &:not(.v-tab--selected) { + /* stylelint-disable-next-line no-descending-specificity */ + &.v-btn.v-btn--variant-text { + &:hover { + color: rgb(var(--v-theme-primary)); + } + } + } + + &.v-tab--selected { + @include mixins.elevation(2); + } + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_textarea.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_textarea.scss new file mode 100755 index 0000000..c9890aa --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_textarea.scss @@ -0,0 +1 @@ +// 👉 Text Area diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_timeline.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_timeline.scss new file mode 100755 index 0000000..1d4f108 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_timeline.scss @@ -0,0 +1,52 @@ +@use "@configured-variables" as variables; +@use "sass:map"; +@use "@styles/variables/vuetify"; +@use "@core/scss/base/mixins"; +@use "@core/scss/base/utils"; + +// 👉 Timeline + +.v-timeline { + &:not(.v-timeline--variant-outlined) .v-timeline-divider__dot { + background: none !important; + + .v-timeline-divider__inner-dot { + box-shadow: 0 0 0 0.1875rem rgb(var(--v-theme-on-surface-variant)); + + @each $color-name in variables.$theme-colors-name { + + &.bg-#{$color-name} { + box-shadow: 0 0 0 0.1875rem rgba(var(--v-theme-#{$color-name}), 0.12); + } + } + } + } + + .v-timeline-item { + .timeline-chip { + border-radius: 6px; + background: rgba(var(--v-theme-on-surface), var(--v-hover-opacity)); + padding-block: 5px; + padding-inline: 10px; + } + } + + &.v-timeline--variant-outlined { + .v-timeline-item { + .v-timeline-divider { + .v-timeline-divider__dot { + background: none !important; + } + } + + .v-timeline-divider__after { + border: 1px dashed rgba(var(--v-border-color), var(--v-border-opacity)); + background: none; + } + + .v-timeline-divider__before { + background: none; + } + } + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/_tooltip.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/_tooltip.scss new file mode 100755 index 0000000..d7a00b6 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/_tooltip.scss @@ -0,0 +1,7 @@ +// 👉 Tooltip + +.v-tooltip { + .v-overlay__content { + font-weight: 500; + } +} diff --git a/src/admin/src/@core/scss/template/libs/vuetify/components/index.scss b/src/admin/src/@core/scss/template/libs/vuetify/components/index.scss new file mode 100755 index 0000000..bf7a79c --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/components/index.scss @@ -0,0 +1,25 @@ +@use "alert"; +@use "avatar"; +@use "button"; +@use "badge"; +@use "cards"; +@use "chip"; +@use "dialog"; +@use "expansion-panels"; +@use "list"; +@use "menu"; +@use "pagination"; +@use "progress"; +@use "rating"; +@use "snackbar"; +@use "slider"; +@use "table"; +@use "tabs"; +@use "timeline"; +@use "tooltip"; +@use "otp-input"; +@use "field"; +@use "checkbox"; +@use "textarea"; +@use "radio"; +@use "switch"; diff --git a/src/admin/src/@core/scss/template/libs/vuetify/index.scss b/src/admin/src/@core/scss/template/libs/vuetify/index.scss new file mode 100755 index 0000000..57045f0 --- /dev/null +++ b/src/admin/src/@core/scss/template/libs/vuetify/index.scss @@ -0,0 +1,3 @@ +@use "@core/scss/base/libs/vuetify"; +@use "overrides"; +@use "components/index"; diff --git a/src/admin/src/@core/scss/template/pages/misc.scss b/src/admin/src/@core/scss/template/pages/misc.scss new file mode 100755 index 0000000..320e8b9 --- /dev/null +++ b/src/admin/src/@core/scss/template/pages/misc.scss @@ -0,0 +1,36 @@ +.layout-blank { + .misc-wrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 1.25rem; + min-block-size: 100dvh; + + .misc-footer-img { + position: absolute; + inline-size: 100%; + inset-block-end: 0; + inset-inline-start: 0; + } + + .misc-footer-tree, .misc-footer-tree-1 { + position: absolute; + } + + .misc-footer-tree { + inset-block-end: 3.75rem; + inset-inline-start: 3.75rem; + } + + .misc-footer-tree-1 { + inset-block-end: 5rem; + inset-inline-end: 4.75rem; + } + + } + + .misc-avatar { + z-index: 1; + } +} diff --git a/src/admin/src/@core/scss/template/pages/page-auth.scss b/src/admin/src/@core/scss/template/pages/page-auth.scss new file mode 100755 index 0000000..d3c6df2 --- /dev/null +++ b/src/admin/src/@core/scss/template/pages/page-auth.scss @@ -0,0 +1,61 @@ +.layout-blank { + .auth-wrapper { + min-block-size: 100dvh; + } + + .auth-footer-mask { + position: absolute; + inset-block-end: 0; + max-inline-size: 100%; + min-inline-size: 100%; + } + + .auth-footer-tree{ + position: absolute !important; + inset-block-end: 70px; + inset-inline-start: 70px; + } + + .auth-footer-start-tree, .auth-footer-end-tree{ + position: absolute !important; + z-index: 1 !important; + } + + .auth-footer-start-tree{ + inset-block-end: 3.75rem; + inset-inline-start: 3.75rem; + } + + .auth-footer-end-tree{ + inset-block-end: 4.625rem; + inset-inline-end: 5rem; + } + + .auth-card, .auth-card-v2, .auth-illustration { + z-index: 1 !important; + } +} + +@media (min-width: 960px) { + .skin--bordered { + .auth-card-v2 { + border-inline-start: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)) !important; + } + } +} + + +.auth-logo { + position: absolute; + z-index: 2; + inset-block-start: 2rem; + inset-inline-start: 2.3rem; +} + +.auth-title{ + font-size: 1.5rem; + font-weight: 600; + letter-spacing: 0.273px; + line-height: normal; + text-transform: capitalize; +} diff --git a/src/admin/src/@core/scss/template/placeholders/_default-layout-vertical-nav.scss b/src/admin/src/@core/scss/template/placeholders/_default-layout-vertical-nav.scss new file mode 100755 index 0000000..b169d48 --- /dev/null +++ b/src/admin/src/@core/scss/template/placeholders/_default-layout-vertical-nav.scss @@ -0,0 +1,11 @@ +@use "@configured-variables" as variables; +@use "@core/scss/base/mixins"; + +%default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled { + box-shadow: 0 4px 8px -4px rgba(var(--v-shadow-key-umbra-color), 42%); + + // If navbar is contained => Squeeze navbar content on scroll + @if variables.$layout-vertical-nav-navbar-is-contained { + padding-inline: 1.5rem; + } +} diff --git a/src/admin/src/@core/scss/template/placeholders/_index.scss b/src/admin/src/@core/scss/template/placeholders/_index.scss new file mode 100755 index 0000000..112293d --- /dev/null +++ b/src/admin/src/@core/scss/template/placeholders/_index.scss @@ -0,0 +1,5 @@ + +@forward "nav"; +@forward "default-layout-vertical-nav"; +@forward "vertical-nav"; +@forward "misc"; diff --git a/src/admin/src/@core/scss/template/placeholders/_misc.scss b/src/admin/src/@core/scss/template/placeholders/_misc.scss new file mode 100755 index 0000000..b826e00 --- /dev/null +++ b/src/admin/src/@core/scss/template/placeholders/_misc.scss @@ -0,0 +1,7 @@ +%blurry-bg { + /* stylelint-disable property-no-vendor-prefix */ + -webkit-backdrop-filter: blur(9px); + backdrop-filter: blur(9px); + /* stylelint-enable */ + background-color: rgb(var(--v-theme-surface), 0.85); +} diff --git a/src/admin/src/@core/scss/template/placeholders/_nav.scss b/src/admin/src/@core/scss/template/placeholders/_nav.scss new file mode 100755 index 0000000..dbd5763 --- /dev/null +++ b/src/admin/src/@core/scss/template/placeholders/_nav.scss @@ -0,0 +1,17 @@ +@use "@core/scss/base/mixins"; + +%nav-link-active { + background: linear-gradient(-72.47deg, rgb(var(--v-theme-primary)) 22.16%, + rgba(var(--v-theme-primary), 0.7) 76.47%) !important; + + i { color: rgb(var(--v-theme-on-primary)) !important; } + + @include mixins.elevation(4); +} + +// ℹ️ This is common style that needs to be applied to both navs +%nav { + .nav-item-title { + line-height: 1.375rem; + } +} diff --git a/src/admin/src/@core/scss/template/placeholders/_vertical-nav.scss b/src/admin/src/@core/scss/template/placeholders/_vertical-nav.scss new file mode 100755 index 0000000..6eab159 --- /dev/null +++ b/src/admin/src/@core/scss/template/placeholders/_vertical-nav.scss @@ -0,0 +1,94 @@ +@use "@configured-variables" as variables; + +%nav-header-action { + color:rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + font-size: 0; +} + +// ℹ️ Add divider around section title +%vertical-nav-section-title { + block-size: 2rem; + font-size: 0.8125rem; + line-height: 1.125rem; + + /* + ℹ️ We will use this to add gap between divider and text. + Moreover, we will use this to adjust the `flex-basis` property of left divider + */ + $divider-gap: 0.625rem; + + // Thanks: https://stackoverflow.com/a/62359101/10796681 + .title-text { + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-start; + column-gap: $divider-gap; + + &::before, + &::after { + border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); + content: ""; + } + + &::after { + flex: 1 1 auto; + } + + &::before { + flex: 0 1 calc(variables.$vertical-nav-horizontal-padding-start - $divider-gap); + margin-inline-start: -#{variables.$vertical-nav-horizontal-padding-start}; + } + } + + // ℹ️ Update the margin-inline-end when vertical nav is in mini state. We done same for link & group. + @at-root { + .layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) .nav-section-title { + margin-inline: 4px 0; + } + } +} + +%vertical-nav-item-interactive { + // Add pill shape styles + block-size: 2.375rem !important; + border-end-end-radius: 3.125rem !important; + border-end-start-radius: 0 !important; + border-start-end-radius: 3.125rem !important; + border-start-start-radius: 0 !important; + + // ℹ️ Wobble effect + transition: margin-inline 0.15s ease-in-out; + will-change: margin-inline; + + // Reduce margin inline end when vertical nav is in collapsed mode and not hovered + .layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) & { + margin-inline: 0 5px; + } +} + +// Vertical nav item badge styles +%vertical-nav-item-badge { + font-size: .8125rem; + line-height: 20px; + padding-block: 0.125rem; + padding-inline: 0.75rem; +} + +// Nav items styles (including section title) +%vertical-nav-item { + gap: .5rem; + padding-block: 0.4375rem; +} + + +// ℹ️ Icon styling for icon nested inside another nav item (2nd level) +%vertical-nav-items-nested-icon { + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + margin-inline: .375rem; +} + +%vertical-nav-items-icon-after-2nd-level { + margin-inline-start: 1rem; + visibility: visible; +} diff --git a/src/admin/src/@core/utils/colorConverter.ts b/src/admin/src/@core/utils/colorConverter.ts new file mode 100755 index 0000000..06380f6 --- /dev/null +++ b/src/admin/src/@core/utils/colorConverter.ts @@ -0,0 +1,35 @@ +/** + * Convert Hex color to rgb + * @param hex + */ + +export const hexToRgb = (hex: string) => { +// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i + + hex = hex.replace(shorthandRegex, (m: string, r: string, g: string, b: string) => { + return r + r + g + g + b + b + }) + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) + + return result ? `${Number.parseInt(result[1], 16)},${Number.parseInt(result[2], 16)},${Number.parseInt(result[3], 16)}` : null +} + +/** + *RGBA color to Hex color with / without opacity + */ +export const rgbaToHex = (rgba: string, forceRemoveAlpha = false) => { + return ( + `#${ + rgba + .replace(/^rgba?\(|\s+|\)$/g, '') // Get's rgba / rgb string values + .split(',') // splits them at "," + .filter((string, index) => !forceRemoveAlpha || index !== 3) + .map(string => Number.parseFloat(string)) // Converts them to numbers + .map((number, index) => (index === 3 ? Math.round(number * 255) : number)) // Converts alpha to 255 number + .map(number => number.toString(16)) // Converts numbers to hex + .map(string => (string.length === 1 ? `0${string}` : string)) // Adds 0 when length of one number is 1 + .join('')}` + ) +} diff --git a/src/admin/src/@core/utils/formatters.ts b/src/admin/src/@core/utils/formatters.ts new file mode 100755 index 0000000..f57d28d --- /dev/null +++ b/src/admin/src/@core/utils/formatters.ts @@ -0,0 +1,6 @@ +// TODO: Try to implement this: https://twitter.com/fireship_dev/status/1565424801216311297 +export const kFormatter = (num: number) => { + const regex = /\B(?=(\d{3})+(?!\d))/g + + return Math.abs(num) > 9999 ? `${Math.sign(num) * +((Math.abs(num) / 1000).toFixed(1))}k` : Math.abs(num).toFixed(0).replace(regex, ',') +} diff --git a/src/admin/src/@core/utils/helpers.ts b/src/admin/src/@core/utils/helpers.ts new file mode 100755 index 0000000..d8e9929 --- /dev/null +++ b/src/admin/src/@core/utils/helpers.ts @@ -0,0 +1,32 @@ +// 👉 IsEmpty +export const isEmpty = (value: unknown): boolean => { + if (value === null || value === undefined || value === '') + return true + + return !!(Array.isArray(value) && value.length === 0) +} + +// 👉 IsNullOrUndefined +export const isNullOrUndefined = (value: unknown): value is undefined | null => { + return value === null || value === undefined +} + +// 👉 IsEmptyArray +export const isEmptyArray = (arr: unknown): boolean => { + return Array.isArray(arr) && arr.length === 0 +} + +// 👉 IsObject +export const isObject = (obj: unknown): obj is Record => + obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj) + +// 👉 IsToday +export const isToday = (date: Date) => { + const today = new Date() + + return ( + date.getDate() === today.getDate() + && date.getMonth() === today.getMonth() + && date.getFullYear() === today.getFullYear() + ) +} diff --git a/src/admin/src/@core/utils/plugins.ts b/src/admin/src/@core/utils/plugins.ts new file mode 100755 index 0000000..52cba91 --- /dev/null +++ b/src/admin/src/@core/utils/plugins.ts @@ -0,0 +1,54 @@ +import type { App } from 'vue' + +/** + * This is helper function to register plugins like a nuxt + * To register a plugin just export a const function `defineVuePlugin` that takes `app` as argument and call `app.use` + * For Scanning plugins it will include all files in `src/plugins` and `src/plugins/**\/index.ts` + * + * + * @param {App} app Vue app instance + * @returns void + * + * @example + * ```ts + * // File: src/plugins/vuetify/index.ts + * + * import type { App } from 'vue' + * import { createVuetify } from 'vuetify' + * + * const vuetify = createVuetify({ ... }) + * + * export default function (app: App) { + * app.use(vuetify) + * } + * ``` + * + * All you have to do is use this helper function in `main.ts` file like below: + * ```ts + * // File: src/main.ts + * import { registerPlugins } from '@core/utils/plugins' + * import { createApp } from 'vue' + * import App from '@/App.vue' + * + * // Create vue app + * const app = createApp(App) + * + * // Register plugins + * registerPlugins(app) // [!code focus] + * + * // Mount vue app + * app.mount('#app') + * ``` + */ + +export const registerPlugins = (app: App) => { + const imports = import.meta.glob<{ default: (app: App) => void }>(['../../plugins/*.{ts,js}', '../../plugins/*/index.{ts,js}'], { eager: true }) + + const importPaths = Object.keys(imports).sort() + + importPaths.forEach(path => { + const pluginImportModule = imports[path] + + pluginImportModule.default?.(app) + }) +} diff --git a/src/admin/src/@layouts/components.ts b/src/admin/src/@layouts/components.ts new file mode 100755 index 0000000..587fd22 --- /dev/null +++ b/src/admin/src/@layouts/components.ts @@ -0,0 +1,3 @@ +export { default as VerticalNavLayout } from './components/VerticalNavLayout.vue' +export { default as VerticalNavLink } from './components/VerticalNavLink.vue' +export { default as VerticalNavSectionTitle } from './components/VerticalNavSectionTitle.vue' diff --git a/src/admin/src/@layouts/components/TransitionExpand.vue b/src/admin/src/@layouts/components/TransitionExpand.vue new file mode 100755 index 0000000..5cae328 --- /dev/null +++ b/src/admin/src/@layouts/components/TransitionExpand.vue @@ -0,0 +1,92 @@ + + + + + + + diff --git a/src/admin/src/@layouts/components/VerticalNav.vue b/src/admin/src/@layouts/components/VerticalNav.vue new file mode 100755 index 0000000..47cda4b --- /dev/null +++ b/src/admin/src/@layouts/components/VerticalNav.vue @@ -0,0 +1,189 @@ + + + + + + + diff --git a/src/admin/src/@layouts/components/VerticalNavGroup.vue b/src/admin/src/@layouts/components/VerticalNavGroup.vue new file mode 100755 index 0000000..31cc869 --- /dev/null +++ b/src/admin/src/@layouts/components/VerticalNavGroup.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/admin/src/@layouts/components/VerticalNavLayout.vue b/src/admin/src/@layouts/components/VerticalNavLayout.vue new file mode 100755 index 0000000..10b35a2 --- /dev/null +++ b/src/admin/src/@layouts/components/VerticalNavLayout.vue @@ -0,0 +1,209 @@ + + + diff --git a/src/admin/src/@layouts/components/VerticalNavLink.vue b/src/admin/src/@layouts/components/VerticalNavLink.vue new file mode 100755 index 0000000..642ffd2 --- /dev/null +++ b/src/admin/src/@layouts/components/VerticalNavLink.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/admin/src/@layouts/components/VerticalNavSectionTitle.vue b/src/admin/src/@layouts/components/VerticalNavSectionTitle.vue new file mode 100755 index 0000000..821b40e --- /dev/null +++ b/src/admin/src/@layouts/components/VerticalNavSectionTitle.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/admin/src/@layouts/enums.ts b/src/admin/src/@layouts/enums.ts new file mode 100755 index 0000000..434a1aa --- /dev/null +++ b/src/admin/src/@layouts/enums.ts @@ -0,0 +1,27 @@ +export const ContentWidth = { + Fluid: 'fluid', + Boxed: 'boxed', +} as const + +export const NavbarType = { + Sticky: 'sticky', + Static: 'static', + Hidden: 'hidden', +} as const + +export const FooterType = { + Sticky: 'sticky', + Static: 'static', + Hidden: 'hidden', +} as const + +export const AppContentLayoutNav = { + Vertical: 'vertical', + Horizontal: 'horizontal', +} as const + +export const HorizontalNavType = { + Sticky: 'sticky', + Static: 'static', + Hidden: 'hidden', +} as const diff --git a/src/admin/src/@layouts/index.ts b/src/admin/src/@layouts/index.ts new file mode 100755 index 0000000..cb64ac1 --- /dev/null +++ b/src/admin/src/@layouts/index.ts @@ -0,0 +1 @@ +export * from './components' diff --git a/src/admin/src/@layouts/styles/_classes.scss b/src/admin/src/@layouts/styles/_classes.scss new file mode 100755 index 0000000..70074d6 --- /dev/null +++ b/src/admin/src/@layouts/styles/_classes.scss @@ -0,0 +1,3 @@ +.cursor-pointer { + cursor: pointer; +} diff --git a/src/admin/src/@layouts/styles/_default-layout.scss b/src/admin/src/@layouts/styles/_default-layout.scss new file mode 100755 index 0000000..7f12d9a --- /dev/null +++ b/src/admin/src/@layouts/styles/_default-layout.scss @@ -0,0 +1,35 @@ +// These are styles which are both common in layout w/ vertical nav & horizontal nav +@use "@layouts/styles/rtl"; +@use "@layouts/styles/placeholders"; +@use "@layouts/styles/mixins"; +@use "@configured-variables" as variables; + +html, +body { + min-block-size: 100%; +} + +.layout-page-content { + @include mixins.boxed-content(true); + + flex-grow: 1; + + // TODO: Use grid gutter variable here + padding-block: 1.5rem; +} + +.layout-footer { + .footer-content-container { + block-size: variables.$layout-vertical-nav-footer-height; + } + + .layout-footer-sticky & { + position: sticky; + inset-block-end: 0; + will-change: transform; + } + + .layout-footer-hidden & { + display: none; + } +} diff --git a/src/admin/src/@layouts/styles/_global.scss b/src/admin/src/@layouts/styles/_global.scss new file mode 100755 index 0000000..eb6d834 --- /dev/null +++ b/src/admin/src/@layouts/styles/_global.scss @@ -0,0 +1,10 @@ +*, +::before, +::after { + box-sizing: inherit; + background-repeat: no-repeat; +} + +html { + box-sizing: border-box; +} diff --git a/src/admin/src/@layouts/styles/_mixins.scss b/src/admin/src/@layouts/styles/_mixins.scss new file mode 100755 index 0000000..5e9957b --- /dev/null +++ b/src/admin/src/@layouts/styles/_mixins.scss @@ -0,0 +1,30 @@ +@use "placeholders"; +@use "@configured-variables" as variables; + +@mixin rtl { + @if variables.$enable-rtl-styles { + [dir="rtl"] & { + @content; + } + } +} + +@mixin boxed-content($nest-selector: false) { + & { + @extend %boxed-content-spacing; + + @at-root { + @if $nest-selector == false { + .layout-content-width-boxed#{&} { + @extend %boxed-content; + } + } + // stylelint-disable-next-line @stylistic/indentation + @else { + .layout-content-width-boxed & { + @extend %boxed-content; + } + } + } + } +} diff --git a/src/admin/src/@layouts/styles/_placeholders.scss b/src/admin/src/@layouts/styles/_placeholders.scss new file mode 100755 index 0000000..c10e25b --- /dev/null +++ b/src/admin/src/@layouts/styles/_placeholders.scss @@ -0,0 +1,53 @@ +// placeholders +@use "@configured-variables" as variables; + +%boxed-content { + @at-root #{&}-spacing { + // TODO: Use grid gutter variable here + padding-inline: 1.5rem; + } + + inline-size: 100%; + margin-inline: auto; + max-inline-size: variables.$layout-boxed-content-width; +} + +%layout-navbar-hidden { + display: none; +} + +// ℹ️ We created this placeholder even it is being used in just layout w/ vertical nav because in future we might apply style to both navbar & horizontal nav separately +%layout-navbar-sticky { + position: sticky; + inset-block-start: 0; + + // will-change: transform; + // inline-size: 100%; +} + +%style-scroll-bar { + /* width */ + + &::-webkit-scrollbar { + background: rgb(var(--v-theme-surface)); + block-size: 8px; + border-end-end-radius: 14px; + border-start-end-radius: 14px; + inline-size: 4px; + } + + /* Track */ + &::-webkit-scrollbar-track { + background: transparent; + } + + /* Handle */ + &::-webkit-scrollbar-thumb { + border-radius: 0.5rem; + background: rgb(var(--v-theme-perfect-scrollbar-thumb)); + } + + &::-webkit-scrollbar-corner { + display: none; + } +} diff --git a/src/admin/src/@layouts/styles/_rtl.scss b/src/admin/src/@layouts/styles/_rtl.scss new file mode 100755 index 0000000..5031d56 --- /dev/null +++ b/src/admin/src/@layouts/styles/_rtl.scss @@ -0,0 +1,7 @@ +@use "./mixins"; + +.layout-vertical-nav .nav-group-arrow { + @include mixins.rtl { + transform: rotate(180deg); + } +} diff --git a/src/admin/src/@layouts/styles/_variables.scss b/src/admin/src/@layouts/styles/_variables.scss new file mode 100755 index 0000000..565b5d8 --- /dev/null +++ b/src/admin/src/@layouts/styles/_variables.scss @@ -0,0 +1,29 @@ +// @use "@styles/style.scss"; + +// 👉 Vertical nav +$layout-vertical-nav-z-index: 12 !default; +$layout-vertical-nav-width: 260px !default; +$layout-vertical-nav-collapsed-width: 80px !default; +$selector-vertical-nav-mini: ".layout-vertical-nav-collapsed .layout-vertical-nav:not(:hover)"; + +// 👉 Horizontal nav +$layout-horizontal-nav-z-index: 11 !default; +$layout-horizontal-nav-navbar-height: 64px !default; + +// 👉 Navbar +$layout-vertical-nav-navbar-height: 64px !default; +$layout-vertical-nav-navbar-is-contained: true !default; +$layout-vertical-nav-layout-navbar-z-index: 11 !default; +$layout-horizontal-nav-layout-navbar-z-index: 11 !default; + +// 👉 Main content +$layout-boxed-content-width: 1440px !default; + +// 👉Footer +$layout-vertical-nav-footer-height: 56px !default; + +// 👉 Layout overlay +$layout-overlay-z-index: 11 !default; + +// 👉 RTL +$enable-rtl-styles: true !default; diff --git a/src/admin/src/@layouts/styles/index.scss b/src/admin/src/@layouts/styles/index.scss new file mode 100755 index 0000000..4e766d8 --- /dev/null +++ b/src/admin/src/@layouts/styles/index.scss @@ -0,0 +1,3 @@ +@use "global"; +@use "vue3-perfect-scrollbar/style.css"; +@use "classes"; diff --git a/src/admin/src/@layouts/types.ts b/src/admin/src/@layouts/types.ts new file mode 100755 index 0000000..bdb830d --- /dev/null +++ b/src/admin/src/@layouts/types.ts @@ -0,0 +1,59 @@ +import type { RouteLocationRaw } from 'vue-router' + +export interface AclProperties { + action: string + subject: string +} + +// 👉 Vertical nav section title +export interface NavSectionTitle extends Partial { + heading: string +} + +// 👉 Vertical nav link +declare type ATagTargetAttrValues = '_blank' | '_self' | '_parent' | '_top' | 'framename' +declare type ATagRelAttrValues = + | 'alternate' + | 'author' + | 'bookmark' + | 'external' + | 'help' + | 'license' + | 'next' + | 'nofollow' + | 'noopener' + | 'noreferrer' + | 'prev' + | 'search' + | 'tag' + +export interface NavLinkProps { + to?: RouteLocationRaw | string | null + href?: string + target?: ATagTargetAttrValues + rel?: ATagRelAttrValues +} + +export interface NavLink extends NavLinkProps, Partial { + title: string + icon?: unknown + badgeContent?: string + badgeClass?: string + disable?: boolean +} + +// 👉 Vertical nav group +export interface NavGroup extends Partial { + title: string + icon?: unknown + badgeContent?: string + badgeClass?: string + children: (NavLink | NavGroup)[] + disable?: boolean +} + +// 👉 Components ======================== +export interface ThemeSwitcherTheme { + name: string + icon: string +} diff --git a/src/admin/src/@layouts/utils.ts b/src/admin/src/@layouts/utils.ts new file mode 100755 index 0000000..c259337 --- /dev/null +++ b/src/admin/src/@layouts/utils.ts @@ -0,0 +1,17 @@ +/** + * Convert Hex color to rgb + * @param hex + */ + +export const hexToRgb = (hex: string) => { +// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i + + hex = hex.replace(shorthandRegex, (m: string, r: string, g: string, b: string) => { + return r + r + g + g + b + b + }) + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) + + return result ? `${Number.parseInt(result[1], 16)},${Number.parseInt(result[2], 16)},${Number.parseInt(result[3], 16)}` : null +} diff --git a/src/admin/src/App.vue b/src/admin/src/App.vue old mode 100644 new mode 100755 index 75ef139..1caf1b9 --- a/src/admin/src/App.vue +++ b/src/admin/src/App.vue @@ -1,5 +1,5 @@ diff --git a/src/admin/src/api/apiKeys.ts b/src/admin/src/api/apiKeys.ts old mode 100644 new mode 100755 index 75aa472..0032d65 --- a/src/admin/src/api/apiKeys.ts +++ b/src/admin/src/api/apiKeys.ts @@ -3,7 +3,7 @@ import type { ApiKeyResponse, CreateApiKeyRequest, CreateApiKeyResponse } from ' export async function listApiKeys(organizationId: number): Promise { const { data } = await apiClient.get( - `/v1/organisations/${organizationId}/api-keys`, + `/v1/organisation/${organizationId}/api-keys`, ); return data; } @@ -13,12 +13,12 @@ export async function createApiKey( request: CreateApiKeyRequest, ): Promise { const { data } = await apiClient.post( - `/v1/organisations/${organizationId}/api-keys`, + `/v1/organisation/${organizationId}/api-keys`, request, ); return data; } export async function deleteApiKey(organizationId: number, keyId: number): Promise { - await apiClient.delete(`/v1/organisations/${organizationId}/api-keys/${keyId}`); + await apiClient.delete(`/v1/organisation/${organizationId}/api-key/${keyId}`); } diff --git a/src/admin/src/api/auditLogs.ts b/src/admin/src/api/auditLogs.ts old mode 100644 new mode 100755 index 5ecb1e6..e2c94bc --- a/src/admin/src/api/auditLogs.ts +++ b/src/admin/src/api/auditLogs.ts @@ -17,7 +17,7 @@ export async function listAuditLogsByOrganization( filter: AuditLogFilter = {}, ): Promise> { const { data } = await apiClient.get>( - `/v1/organisations/${orgId}/audit-logs`, + `/v1/organisation/${orgId}/audit-logs`, { params: toParams(filter) }, ); return data; @@ -28,7 +28,7 @@ export async function listAuditLogsByProject( filter: AuditLogFilter = {}, ): Promise> { const { data } = await apiClient.get>( - `/v1/projects/${projectId}/audit-logs`, + `/v1/project/${projectId}/audit-logs`, { params: toParams(filter) }, ); return data; diff --git a/src/admin/src/api/auth.ts b/src/admin/src/api/auth.ts old mode 100644 new mode 100755 diff --git a/src/admin/src/api/client.ts b/src/admin/src/api/client.ts old mode 100644 new mode 100755 diff --git a/src/admin/src/api/environments.ts b/src/admin/src/api/environments.ts old mode 100644 new mode 100755 index 0238e61..952810b --- a/src/admin/src/api/environments.ts +++ b/src/admin/src/api/environments.ts @@ -16,7 +16,7 @@ export async function listEnvironments(projectId: number, page = 1, pageSize = 1 } export async function getEnvironment(apiKey: string): Promise { - const { data } = await apiClient.get(`/v1/environments/${apiKey}`); + const { data } = await apiClient.get(`/v1/environment/${apiKey}`); return data; } @@ -26,17 +26,17 @@ export async function createEnvironment(request: CreateEnvironmentRequest): Prom } export async function updateEnvironment(apiKey: string, request: UpdateEnvironmentRequest): Promise { - const { data } = await apiClient.put(`/v1/environments/${apiKey}`, request); + const { data } = await apiClient.put(`/v1/environment/${apiKey}`, request); return data; } export async function deleteEnvironment(apiKey: string): Promise { - await apiClient.delete(`/v1/environments/${apiKey}`); + await apiClient.delete(`/v1/environment/${apiKey}`); } export async function cloneEnvironment(apiKey: string, request: CloneEnvironmentRequest): Promise { const { data } = await apiClient.post( - `/v1/environments/${apiKey}/clone`, + `/v1/environment/${apiKey}/clone`, request, ); return data; diff --git a/src/admin/src/api/featureSegments.ts b/src/admin/src/api/featureSegments.ts old mode 100644 new mode 100755 index 3847b67..b68ca75 --- a/src/admin/src/api/featureSegments.ts +++ b/src/admin/src/api/featureSegments.ts @@ -11,7 +11,7 @@ export async function listFeatureSegments( featureId: number, ): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/features/${featureId}/segments`, + `/v1/environment/${envApiKey}/feature/${featureId}/segments`, ); return data; } @@ -22,7 +22,7 @@ export async function createFeatureSegment( request: CreateFeatureSegmentRequest, ): Promise { const { data } = await apiClient.post( - `/v1/environments/${envApiKey}/features/${featureId}/segments`, + `/v1/environment/${envApiKey}/feature/${featureId}/segments`, request, ); return data; @@ -35,7 +35,7 @@ export async function updateFeatureSegment( request: UpdateFeatureSegmentRequest, ): Promise { const { data } = await apiClient.put( - `/v1/environments/${envApiKey}/features/${featureId}/segments/${id}`, + `/v1/environment/${envApiKey}/feature/${featureId}/segment/${id}`, request, ); return data; @@ -46,7 +46,7 @@ export async function deleteFeatureSegment( featureId: number, id: number, ): Promise { - await apiClient.delete(`/v1/environments/${envApiKey}/features/${featureId}/segments/${id}`); + await apiClient.delete(`/v1/environment/${envApiKey}/feature/${featureId}/segment/${id}`); } export async function listIdentitySegments( @@ -54,7 +54,7 @@ export async function listIdentitySegments( identityId: number, ): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/identities/${identityId}/segments`, + `/v1/environment/${envApiKey}/identity/${identityId}/segments`, ); return data; } diff --git a/src/admin/src/api/featureStates.ts b/src/admin/src/api/featureStates.ts old mode 100644 new mode 100755 index 2c8e122..8451d28 --- a/src/admin/src/api/featureStates.ts +++ b/src/admin/src/api/featureStates.ts @@ -7,14 +7,14 @@ import type { export async function listFeatureStates(envApiKey: string): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/featurestates`, + `/v1/environment/${envApiKey}/featurestates`, ); return data; } export async function getFeatureState(envApiKey: string, id: number): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/featurestates/${id}`, + `/v1/environment/${envApiKey}/featurestate/${id}`, ); return data; } @@ -25,7 +25,7 @@ export async function updateFeatureState( request: UpdateFeatureStateRequest, ): Promise { const { data } = await apiClient.put( - `/v1/environments/${envApiKey}/featurestates/${id}`, + `/v1/environment/${envApiKey}/featurestate/${id}`, request, ); return data; @@ -37,7 +37,7 @@ export async function patchFeatureState( request: PatchFeatureStateRequest, ): Promise { const { data } = await apiClient.patch( - `/v1/environments/${envApiKey}/featurestates/${id}`, + `/v1/environment/${envApiKey}/featurestate/${id}`, request, ); return data; diff --git a/src/admin/src/api/features.ts b/src/admin/src/api/features.ts old mode 100644 new mode 100755 index d013ac7..5b1f8f6 --- a/src/admin/src/api/features.ts +++ b/src/admin/src/api/features.ts @@ -13,7 +13,7 @@ export async function listFeatures( pageSize = 100, ): Promise> { const { data } = await apiClient.get>( - `/v1/projects/${projectId}/features`, + `/v1/project/${projectId}/features`, { params: { page, pageSize } }, ); return data; @@ -21,7 +21,7 @@ export async function listFeatures( export async function getFeature(projectId: number, id: number): Promise { const { data } = await apiClient.get( - `/v1/projects/${projectId}/features/${id}`, + `/v1/project/${projectId}/feature/${id}`, ); return data; } @@ -31,7 +31,7 @@ export async function createFeature( request: CreateFeatureRequest, ): Promise { const { data } = await apiClient.post( - `/v1/projects/${projectId}/features`, + `/v1/project/${projectId}/features`, request, ); return data; @@ -43,7 +43,7 @@ export async function updateFeature( request: UpdateFeatureRequest, ): Promise { const { data } = await apiClient.put( - `/v1/projects/${projectId}/features/${id}`, + `/v1/project/${projectId}/feature/${id}`, request, ); return data; @@ -55,12 +55,34 @@ export async function patchFeature( request: PatchFeatureRequest, ): Promise { const { data } = await apiClient.patch( - `/v1/projects/${projectId}/features/${id}`, + `/v1/project/${projectId}/feature/${id}`, request, ); return data; } export async function deleteFeature(projectId: number, id: number): Promise { - await apiClient.delete(`/v1/projects/${projectId}/features/${id}`); + await apiClient.delete(`/v1/project/${projectId}/feature/${id}`); +} + +export async function assignFeatureTag( + projectId: number, + featureId: number, + tagId: number, +): Promise { + const { data } = await apiClient.put( + `/v1/project/${projectId}/feature/${featureId}/tag/${tagId}`, + ); + return data; +} + +export async function removeFeatureTag( + projectId: number, + featureId: number, + tagId: number, +): Promise { + const { data } = await apiClient.delete( + `/v1/project/${projectId}/feature/${featureId}/tag/${tagId}`, + ); + return data; } diff --git a/src/admin/src/api/identities.ts b/src/admin/src/api/identities.ts old mode 100644 new mode 100755 index 1b2a987..71230f0 --- a/src/admin/src/api/identities.ts +++ b/src/admin/src/api/identities.ts @@ -15,7 +15,7 @@ export async function listIdentities( pageSize = 100, ): Promise> { const { data } = await apiClient.get>( - `/v1/environments/${envApiKey}/identities`, + `/v1/environment/${envApiKey}/identities`, { params: { page, pageSize } }, ); return data; @@ -26,7 +26,7 @@ export async function createIdentity( request: CreateIdentityRequest, ): Promise { const { data } = await apiClient.post( - `/v1/environments/${envApiKey}/identities`, + `/v1/environment/${envApiKey}/identities`, request, ); return data; @@ -34,7 +34,7 @@ export async function createIdentity( export async function getIdentity(envApiKey: string, id: number): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/identities/${id}`, + `/v1/environment/${envApiKey}/identity/${id}`, ); return data; } @@ -46,7 +46,7 @@ export async function upsertIdentityTrait( request: UpsertTraitRequest, ): Promise { const { data } = await apiClient.put( - `/v1/environments/${envApiKey}/identities/${identityId}/traits/${encodeURIComponent(key)}`, + `/v1/environment/${envApiKey}/identity/${identityId}/trait/${encodeURIComponent(key)}`, request, ); return data; @@ -58,12 +58,12 @@ export async function deleteIdentityTrait( key: string, ): Promise { await apiClient.delete( - `/v1/environments/${envApiKey}/identities/${identityId}/traits/${encodeURIComponent(key)}`, + `/v1/environment/${envApiKey}/identity/${identityId}/trait/${encodeURIComponent(key)}`, ); } export async function deleteIdentity(envApiKey: string, id: number): Promise { - await apiClient.delete(`/v1/environments/${envApiKey}/identities/${id}`); + await apiClient.delete(`/v1/environment/${envApiKey}/identity/${id}`); } export async function getIdentityFeatureStates( @@ -71,7 +71,7 @@ export async function getIdentityFeatureStates( identityId: number, ): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/identities/${identityId}/featurestates`, + `/v1/environment/${envApiKey}/identity/${identityId}/featurestates`, ); return data; } @@ -83,7 +83,7 @@ export async function setIdentityFeatureState( request: UpdateFeatureStateRequest, ): Promise { const { data } = await apiClient.put( - `/v1/environments/${envApiKey}/identities/${identityId}/featurestates/${featureId}`, + `/v1/environment/${envApiKey}/identity/${identityId}/featurestate/${featureId}`, request, ); return data; @@ -95,6 +95,6 @@ export async function deleteIdentityFeatureState( featureId: number, ): Promise { await apiClient.delete( - `/v1/environments/${envApiKey}/identities/${identityId}/featurestates/${featureId}`, + `/v1/environment/${envApiKey}/identity/${identityId}/featurestate/${featureId}`, ); } diff --git a/src/admin/src/api/organizations.ts b/src/admin/src/api/organizations.ts old mode 100644 new mode 100755 index ba77a52..7d36d22 --- a/src/admin/src/api/organizations.ts +++ b/src/admin/src/api/organizations.ts @@ -5,6 +5,9 @@ import type { UpdateOrganizationRequest, OrganizationMemberResponse, InviteUserRequest, + InviteUsersByEmailRequest, + InviteByEmailResult, + InviteTokenResponse, PaginatedResponse, } from '@/types/api'; @@ -17,7 +20,7 @@ export async function listOrganizations(page = 1, pageSize = 100): Promise { - const { data } = await apiClient.get(`/v1/organisations/${id}`); + const { data } = await apiClient.get(`/v1/organisation/${id}`); return data; } @@ -27,25 +30,58 @@ export async function createOrganization(request: CreateOrganizationRequest): Pr } export async function updateOrganization(id: number, request: UpdateOrganizationRequest): Promise { - const { data } = await apiClient.put(`/v1/organisations/${id}`, request); + const { data } = await apiClient.put(`/v1/organisation/${id}`, request); return data; } export async function deleteOrganization(id: number): Promise { - await apiClient.delete(`/v1/organisations/${id}`); + await apiClient.delete(`/v1/organisation/${id}`); } export async function listOrganizationMembers(organizationId: number): Promise { const { data } = await apiClient.get( - `/v1/organisations/${organizationId}/users`, + `/v1/organisation/${organizationId}/users`, ); return data; } export async function inviteOrganizationMember(organizationId: number, request: InviteUserRequest): Promise { - await apiClient.post(`/v1/organisations/${organizationId}/users/invite`, request); + await apiClient.post(`/v1/organisation/${organizationId}/users/invite`, request); } export async function removeOrganizationMember(organizationId: number, userId: number): Promise { - await apiClient.delete(`/v1/organisations/${organizationId}/users/${userId}`); + await apiClient.delete(`/v1/organisation/${organizationId}/user/${userId}`); +} + +export async function inviteOrganizationMembersByEmail( + organizationId: number, + request: InviteUsersByEmailRequest, +): Promise { + const { data } = await apiClient.post( + `/v1/organisation/${organizationId}/users/invite-by-email`, + request, + ); + return data; +} + +export async function getInviteLink(organizationId: number): Promise { + const { data } = await apiClient.get( + `/v1/organisation/${organizationId}/invite-link`, + ); + return data; +} + +export async function regenerateInviteLink(organizationId: number): Promise { + const { data } = await apiClient.post( + `/v1/organisation/${organizationId}/invite-link/regenerate`, + ); + return data; +} + +export async function acceptInvite(token: string): Promise { + await apiClient.post(`/v1/organisations/invite/${token}/accept`); +} + +export async function setPrimaryOrganization(id: number): Promise { + await apiClient.put(`/v1/organisation/${id}/primary`); } diff --git a/src/admin/src/api/projects.ts b/src/admin/src/api/projects.ts old mode 100644 new mode 100755 index 6b0c2e4..90983d6 --- a/src/admin/src/api/projects.ts +++ b/src/admin/src/api/projects.ts @@ -17,7 +17,7 @@ export async function listProjects(organizationId: number, page = 1, pageSize = } export async function getProject(id: number): Promise { - const { data } = await apiClient.get(`/v1/projects/${id}`); + const { data } = await apiClient.get(`/v1/project/${id}`); return data; } @@ -27,17 +27,17 @@ export async function createProject(request: CreateProjectRequest): Promise { - const { data } = await apiClient.put(`/v1/projects/${id}`, request); + const { data } = await apiClient.put(`/v1/project/${id}`, request); return data; } export async function deleteProject(id: number): Promise { - await apiClient.delete(`/v1/projects/${id}`); + await apiClient.delete(`/v1/project/${id}`); } export async function listProjectUserPermissions(projectId: number): Promise { const { data } = await apiClient.get( - `/v1/projects/${projectId}/user-permissions`, + `/v1/project/${projectId}/user-permissions`, ); return data; } @@ -47,7 +47,7 @@ export async function setProjectUserPermissions( request: SetUserPermissionsRequest, ): Promise { const { data } = await apiClient.post( - `/v1/projects/${projectId}/user-permissions`, + `/v1/project/${projectId}/user-permissions`, request, ); return data; @@ -59,12 +59,12 @@ export async function updateProjectUserPermissions( request: SetUserPermissionsRequest, ): Promise { const { data } = await apiClient.put( - `/v1/projects/${projectId}/user-permissions/${userId}`, + `/v1/project/${projectId}/user-permission/${userId}`, request, ); return data; } export async function removeProjectUserPermissions(projectId: number, userId: number): Promise { - await apiClient.delete(`/v1/projects/${projectId}/user-permissions/${userId}`); + await apiClient.delete(`/v1/project/${projectId}/user-permission/${userId}`); } diff --git a/src/admin/src/api/segments.ts b/src/admin/src/api/segments.ts old mode 100644 new mode 100755 index 32a4b05..7127077 --- a/src/admin/src/api/segments.ts +++ b/src/admin/src/api/segments.ts @@ -8,7 +8,7 @@ import type { export async function listSegments(projectId: number, page = 1, pageSize = 100): Promise { const { data } = await apiClient.get>( - `/v1/projects/${projectId}/segments`, + `/v1/project/${projectId}/segments`, { params: { page, pageSize } }, ); return data.results; @@ -16,7 +16,7 @@ export async function listSegments(projectId: number, page = 1, pageSize = 100): export async function getSegment(projectId: number, id: number): Promise { const { data } = await apiClient.get( - `/v1/projects/${projectId}/segments/${id}`, + `/v1/project/${projectId}/segment/${id}`, ); return data; } @@ -26,7 +26,7 @@ export async function createSegment( request: CreateSegmentRequest, ): Promise { const { data } = await apiClient.post( - `/v1/projects/${projectId}/segments`, + `/v1/project/${projectId}/segments`, request, ); return data; @@ -38,12 +38,12 @@ export async function updateSegment( request: UpdateSegmentRequest, ): Promise { const { data } = await apiClient.put( - `/v1/projects/${projectId}/segments/${id}`, + `/v1/project/${projectId}/segment/${id}`, request, ); return data; } export async function deleteSegment(projectId: number, id: number): Promise { - await apiClient.delete(`/v1/projects/${projectId}/segments/${id}`); + await apiClient.delete(`/v1/project/${projectId}/segment/${id}`); } diff --git a/src/admin/src/api/tags.ts b/src/admin/src/api/tags.ts old mode 100644 new mode 100755 index ea704ae..3961c9e --- a/src/admin/src/api/tags.ts +++ b/src/admin/src/api/tags.ts @@ -2,15 +2,15 @@ import apiClient from './client'; import type { TagResponse, CreateTagRequest } from '@/types/api'; export async function listTags(projectId: number): Promise { - const { data } = await apiClient.get(`/v1/projects/${projectId}/tags`); + const { data } = await apiClient.get(`/v1/project/${projectId}/tags`); return data; } export async function createTag(projectId: number, request: CreateTagRequest): Promise { - const { data } = await apiClient.post(`/v1/projects/${projectId}/tags`, request); + const { data } = await apiClient.post(`/v1/project/${projectId}/tags`, request); return data; } export async function deleteTag(projectId: number, id: number): Promise { - await apiClient.delete(`/v1/projects/${projectId}/tags/${id}`); + await apiClient.delete(`/v1/project/${projectId}/tag/${id}`); } diff --git a/src/admin/src/api/usage.ts b/src/admin/src/api/usage.ts new file mode 100644 index 0000000..73c00c1 --- /dev/null +++ b/src/admin/src/api/usage.ts @@ -0,0 +1,7 @@ +import apiClient from './client'; +import type { DashboardUsageResponse } from '@/types/api'; + +export async function getUsageDashboard(environmentId: number, days = 14): Promise { + const { data } = await apiClient.get(`/v1/environment/${environmentId}/usage`, { params: { days } }); + return data; +} diff --git a/src/admin/src/api/users.ts b/src/admin/src/api/users.ts new file mode 100755 index 0000000..0f8c041 --- /dev/null +++ b/src/admin/src/api/users.ts @@ -0,0 +1,21 @@ +import apiClient from './client'; +import type { UserProfileResponse, UpdateProfileRequest, ChangePasswordRequest } from '@/types/api'; + +export async function getMe(): Promise { + const { data } = await apiClient.get('/v1/user/me'); + return data; +} + +export async function updateMe(request: UpdateProfileRequest): Promise { + const { data } = await apiClient.put('/v1/user/me', request); + return data; +} + +export async function changePassword(request: ChangePasswordRequest): Promise { + await apiClient.post('/v1/user/me/change-password', request); +} + +export async function getUserById(id: number): Promise { + const { data } = await apiClient.get(`/v1/user/${id}`); + return data; +} diff --git a/src/admin/src/api/webhooks.ts b/src/admin/src/api/webhooks.ts old mode 100644 new mode 100755 index 2558f71..4a16af9 --- a/src/admin/src/api/webhooks.ts +++ b/src/admin/src/api/webhooks.ts @@ -8,7 +8,7 @@ import type { // ─── Organization webhooks ──────────────────────────────────────────────────── export async function listOrgWebhooks(orgId: number): Promise { - const { data } = await apiClient.get(`/v1/organisations/${orgId}/webhooks`); + const { data } = await apiClient.get(`/v1/organisation/${orgId}/webhooks`); return data; } @@ -17,7 +17,7 @@ export async function createOrgWebhook( request: CreateWebhookRequest, ): Promise { const { data } = await apiClient.post( - `/v1/organisations/${orgId}/webhooks`, + `/v1/organisation/${orgId}/webhooks`, request, ); return data; @@ -29,21 +29,21 @@ export async function updateOrgWebhook( request: CreateWebhookRequest, ): Promise { const { data } = await apiClient.put( - `/v1/organisations/${orgId}/webhooks/${webhookId}`, + `/v1/organisation/${orgId}/webhook/${webhookId}`, request, ); return data; } export async function deleteOrgWebhook(orgId: number, webhookId: number): Promise { - await apiClient.delete(`/v1/organisations/${orgId}/webhooks/${webhookId}`); + await apiClient.delete(`/v1/organisation/${orgId}/webhook/${webhookId}`); } // ─── Environment webhooks ───────────────────────────────────────────────────── export async function listEnvWebhooks(envApiKey: string): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/webhooks`, + `/v1/environment/${envApiKey}/webhooks`, ); return data; } @@ -53,7 +53,7 @@ export async function createEnvWebhook( request: CreateWebhookRequest, ): Promise { const { data } = await apiClient.post( - `/v1/environments/${envApiKey}/webhooks`, + `/v1/environment/${envApiKey}/webhooks`, request, ); return data; @@ -65,14 +65,14 @@ export async function updateEnvWebhook( request: CreateWebhookRequest, ): Promise { const { data } = await apiClient.put( - `/v1/environments/${envApiKey}/webhooks/${webhookId}`, + `/v1/environment/${envApiKey}/webhook/${webhookId}`, request, ); return data; } export async function deleteEnvWebhook(envApiKey: string, webhookId: number): Promise { - await apiClient.delete(`/v1/environments/${envApiKey}/webhooks/${webhookId}`); + await apiClient.delete(`/v1/environment/${envApiKey}/webhook/${webhookId}`); } // ─── Delivery logs ──────────────────────────────────────────────────────────── @@ -82,7 +82,7 @@ export async function listWebhookDeliveries( webhookId: number, ): Promise { const { data } = await apiClient.get( - `/v1/environments/${envApiKey}/webhooks/${webhookId}/deliveries`, + `/v1/environment/${envApiKey}/webhook/${webhookId}/deliveries`, ); return data; } diff --git a/src/admin/src/assets/images/logo.svg b/src/admin/src/assets/images/logo.svg new file mode 100755 index 0000000..8fa42ca --- /dev/null +++ b/src/admin/src/assets/images/logo.svg @@ -0,0 +1,40 @@ + + MicCheck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/admin/src/assets/images/svg/checkbox-checked.svg b/src/admin/src/assets/images/svg/checkbox-checked.svg new file mode 100755 index 0000000..dcd5fa8 --- /dev/null +++ b/src/admin/src/assets/images/svg/checkbox-checked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/admin/src/assets/images/svg/checkbox-indeterminate.svg b/src/admin/src/assets/images/svg/checkbox-indeterminate.svg new file mode 100755 index 0000000..d77969d --- /dev/null +++ b/src/admin/src/assets/images/svg/checkbox-indeterminate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/admin/src/assets/images/svg/checkbox-unchecked.svg b/src/admin/src/assets/images/svg/checkbox-unchecked.svg new file mode 100755 index 0000000..5bdd97d --- /dev/null +++ b/src/admin/src/assets/images/svg/checkbox-unchecked.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/admin/src/assets/images/svg/radio-checked.svg b/src/admin/src/assets/images/svg/radio-checked.svg new file mode 100755 index 0000000..4606865 --- /dev/null +++ b/src/admin/src/assets/images/svg/radio-checked.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/admin/src/assets/images/svg/radio-unchecked.svg b/src/admin/src/assets/images/svg/radio-unchecked.svg new file mode 100755 index 0000000..91d0c2a --- /dev/null +++ b/src/admin/src/assets/images/svg/radio-unchecked.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/admin/src/assets/logo.svg b/src/admin/src/assets/logo.svg old mode 100644 new mode 100755 diff --git a/src/admin/src/assets/styles/styles/styles.scss b/src/admin/src/assets/styles/styles/styles.scss new file mode 100755 index 0000000..3118a33 --- /dev/null +++ b/src/admin/src/assets/styles/styles/styles.scss @@ -0,0 +1 @@ +// Write your overrides diff --git a/src/admin/src/assets/styles/styles/variables/_template.scss b/src/admin/src/assets/styles/styles/variables/_template.scss new file mode 100755 index 0000000..087f7fe --- /dev/null +++ b/src/admin/src/assets/styles/styles/variables/_template.scss @@ -0,0 +1,6 @@ +@forward "@core/scss/template/variables"; + +// ℹ️ Remove above import and uncomment below to override core variables. +// @forward "@core/scss/template/variables" with ( +// $: +// ) diff --git a/src/admin/src/assets/styles/styles/variables/_vuetify.scss b/src/admin/src/assets/styles/styles/variables/_vuetify.scss new file mode 100755 index 0000000..325a8e3 --- /dev/null +++ b/src/admin/src/assets/styles/styles/variables/_vuetify.scss @@ -0,0 +1,7 @@ +// ❗ Path must be relative +@forward "../../../@core/scss/template/libs/vuetify/variables"; + +// ℹ️ Remove above import and uncomment below to override core variables. +// @forward "../../../@core/scss/template/libs/vuetify/variables" with ( +// $: +// ) diff --git a/src/admin/src/assets/styles/variables/_template.scss b/src/admin/src/assets/styles/variables/_template.scss new file mode 100755 index 0000000..087f7fe --- /dev/null +++ b/src/admin/src/assets/styles/variables/_template.scss @@ -0,0 +1,6 @@ +@forward "@core/scss/template/variables"; + +// ℹ️ Remove above import and uncomment below to override core variables. +// @forward "@core/scss/template/variables" with ( +// $: +// ) diff --git a/src/admin/src/assets/styles/variables/_vuetify.scss b/src/admin/src/assets/styles/variables/_vuetify.scss new file mode 100755 index 0000000..325a8e3 --- /dev/null +++ b/src/admin/src/assets/styles/variables/_vuetify.scss @@ -0,0 +1,7 @@ +// ❗ Path must be relative +@forward "../../../@core/scss/template/libs/vuetify/variables"; + +// ℹ️ Remove above import and uncomment below to override core variables. +// @forward "../../../@core/scss/template/libs/vuetify/variables" with ( +// $: +// ) diff --git a/src/admin/src/components/AppHeader.vue b/src/admin/src/components/AppHeader.vue deleted file mode 100644 index defb05b..0000000 --- a/src/admin/src/components/AppHeader.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - diff --git a/src/admin/src/components/AppLayout.vue b/src/admin/src/components/AppLayout.vue deleted file mode 100644 index f50d299..0000000 --- a/src/admin/src/components/AppLayout.vue +++ /dev/null @@ -1,142 +0,0 @@ - - - diff --git a/src/admin/src/components/dashboard/DailyUsageChart.vue b/src/admin/src/components/dashboard/DailyUsageChart.vue new file mode 100644 index 0000000..77aa5a9 --- /dev/null +++ b/src/admin/src/components/dashboard/DailyUsageChart.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/admin/src/components/dashboard/TopFeaturesChart.vue b/src/admin/src/components/dashboard/TopFeaturesChart.vue new file mode 100644 index 0000000..7793a42 --- /dev/null +++ b/src/admin/src/components/dashboard/TopFeaturesChart.vue @@ -0,0 +1,49 @@ + + + diff --git a/src/admin/src/components/features/FeatureDetail.vue b/src/admin/src/components/features/FeatureDetail.vue old mode 100644 new mode 100755 index e63fcd0..d8e7cd4 --- a/src/admin/src/components/features/FeatureDetail.vue +++ b/src/admin/src/components/features/FeatureDetail.vue @@ -8,17 +8,18 @@ -
+
+ {{ feature.name }} {{ feature.type }} - {{ feature.name }}
- + @@ -28,7 +29,7 @@ - + @@ -45,7 +46,7 @@
- mdi-server-outline + ri-server-line

Select an environment to manage feature state.

@@ -94,7 +95,7 @@ - +
@@ -113,7 +114,7 @@
- mdi-server-outline + ri-server-line

Select an environment to manage segment overrides.

@@ -130,7 +131,7 @@
- mdi-account-group-outline + ri-group-line {{ fsg.segmentName }} Priority {{ fsg.priority }} @@ -146,7 +147,7 @@ @update:model-value="onUpdateSegmentEnabled(fsg, $event)" />
-
+
+ + Delete feature + - Save settings + Save changes
- - - - Danger Zone - -

- Permanently delete this feature flag. This cannot be undone and will remove - the flag from all environments. -

-

- Type {{ feature.name }} to confirm: -

- - - Delete feature - -
-
@@ -342,6 +319,7 @@ interface Props { modelValue: boolean; feature: FeatureResponse | null; featureState: FeatureStateResponse | null; + initialTab?: string; } const props = defineProps(); @@ -360,7 +338,6 @@ const isTogglingEnabled = ref(false); const isSavingValue = ref(false); const isSavingSettings = ref(false); const isDeleting = ref(false); -const deleteConfirmName = ref(''); const editedValue = ref(null); const settingsFormRef = ref<{ validate: () => Promise<{ valid: boolean }> } | null>(null); const valueErrorMessage = ref(null); @@ -476,7 +453,6 @@ function syncSettingsForm(f: FeatureResponse | null): void { description: f.description ?? '', defaultEnabled: f.defaultEnabled, }; - deleteConfirmName.value = ''; } } @@ -497,7 +473,7 @@ watch( () => props.modelValue, (open) => { if (open) { - activeTab.value = 'value'; + activeTab.value = props.initialTab ?? 'value'; valueErrorMessage.value = null; settingsErrorMessage.value = null; segmentsErrorMessage.value = null; @@ -506,6 +482,7 @@ watch( newSegmentEnabled.value = true; newSegmentPriority.value = 1; syncSettingsForm(props.feature); + editedValue.value = props.featureState?.value ?? null; loadSegmentsData(); } @@ -581,6 +558,10 @@ async function onSaveSettings(): Promise { } } +function onTagsUpdated(updated: FeatureResponse): void { + emit('updated', updated); +} + async function onDelete(): Promise { if (!props.feature || deleteConfirmName.value !== props.feature.name) return; const projectId = contextStore.currentProject?.id; diff --git a/src/admin/src/components/features/FeatureDialog.vue b/src/admin/src/components/features/FeatureDialog.vue old mode 100644 new mode 100755 diff --git a/src/admin/src/components/features/FeatureValueEditor.vue b/src/admin/src/components/features/FeatureValueEditor.vue old mode 100644 new mode 100755 index 112cea6..36bd451 --- a/src/admin/src/components/features/FeatureValueEditor.vue +++ b/src/admin/src/components/features/FeatureValueEditor.vue @@ -1,16 +1,24 @@ + + + - - - @@ -126,7 +130,7 @@
{{ formatJson(item.changes) }}
@@ -136,7 +140,7 @@ @@ -148,7 +152,7 @@ Page {{ page }} of {{ totalPages }} ({{ total }} entries) Organization @@ -31,11 +32,12 @@ :variant="contextStore.currentProject ? 'tonal' : 'outlined'" rounded="lg" data-testid="project-card" + class="context-card" > Project @@ -52,11 +54,12 @@ :variant="contextStore.currentEnvironment ? 'tonal' : 'outlined'" rounded="lg" data-testid="environment-card" + class="context-card" > Environment @@ -68,6 +71,61 @@ + + + + + diff --git a/src/admin/src/views/EnvironmentsView.vue b/src/admin/src/views/EnvironmentsView.vue old mode 100644 new mode 100755 diff --git a/src/admin/src/views/FeaturesView.vue b/src/admin/src/views/FeaturesView.vue old mode 100644 new mode 100755 index dd44dcd..cd3eb0b --- a/src/admin/src/views/FeaturesView.vue +++ b/src/admin/src/views/FeaturesView.vue @@ -5,7 +5,7 @@ @@ -16,7 +16,7 @@ - mdi-flag-outline + ri-flag-line

Select a project

Choose a project from the sidebar to manage its feature flags. @@ -28,7 +28,7 @@ + + + @@ -146,11 +192,37 @@ v-model="showDetail" :feature="selectedFeature" :feature-state="selectedFeatureState" + :initial-tab="detailInitialTab" @updated="onFeatureUpdated" @deleted="onFeatureDeleted" @state-updated="onStateUpdated" /> + + + + Delete feature + +

+ Delete {{ featureToDelete?.name }}? This cannot be undone. +

+
+ + + Cancel + + Delete + + +
+ + import { ref, computed, watch } from 'vue'; -import { listFeatures } from '@/api/features'; +import { listFeatures, deleteFeature } from '@/api/features'; import { listFeatureStates, patchFeatureState } from '@/api/featureStates'; import { listFeatureSegments } from '@/api/featureSegments'; import { useContextStore } from '@/stores/context'; @@ -199,6 +271,12 @@ function showError(message: string): void { const showDialog = ref(false); const showDetail = ref(false); const selectedFeature = ref(null); +const detailInitialTab = ref('value'); + +// Delete dialog state +const showDeleteDialog = ref(false); +const featureToDelete = ref(null); +const isDeletingFromTable = ref(false); const selectedFeatureState = computed(() => selectedFeature.value ? (featureStateMap.value.get(selectedFeature.value.id) ?? null) : null, @@ -211,6 +289,7 @@ const headers = [ { title: 'Enabled', key: 'enabled', sortable: false, width: '100' }, { title: 'Segments', key: 'segments', sortable: false }, { title: 'Created', key: 'createdAt', sortable: true, width: '130' }, + { title: '', key: 'actions', sortable: false, width: '52' }, ]; // ─── Computed ───────────────────────────────────────────────────────────────── @@ -290,6 +369,13 @@ function openCreateDialog(): void { } function onRowClick(_event: Event, { item }: { item: FeatureResponse }): void { + detailInitialTab.value = 'value'; + selectedFeature.value = item; + showDetail.value = true; +} + +function openDetailOnSegments(item: FeatureResponse): void { + detailInitialTab.value = 'segments'; selectedFeature.value = item; showDetail.value = true; } @@ -311,6 +397,32 @@ function onFeatureUpdated(updated: FeatureResponse): void { if (selectedFeature.value?.id === updated.id) selectedFeature.value = updated; } +function openDeleteDialog(feature: FeatureResponse): void { + featureToDelete.value = feature; + showDeleteDialog.value = true; +} + +function closeDeleteDialog(): void { + showDeleteDialog.value = false; + featureToDelete.value = null; +} + +async function onConfirmDelete(): Promise { + const feature = featureToDelete.value; + const projectId = contextStore.currentProject?.id; + if (!feature || !projectId) return; + isDeletingFromTable.value = true; + try { + await deleteFeature(projectId, feature.id); + onFeatureDeleted(feature.id); + closeDeleteDialog(); + } catch { + showError('Failed to delete feature. Please try again.'); + } finally { + isDeletingFromTable.value = false; + } +} + function onFeatureDeleted(featureId: number): void { features.value = features.value.filter((f) => f.id !== featureId); featureStateMap.value.delete(featureId); diff --git a/src/admin/src/views/IdentitiesView.vue b/src/admin/src/views/IdentitiesView.vue old mode 100644 new mode 100755 index 6f992f0..07094bd --- a/src/admin/src/views/IdentitiesView.vue +++ b/src/admin/src/views/IdentitiesView.vue @@ -5,7 +5,7 @@ @@ -16,7 +16,7 @@ - mdi-account-outline + ri-user-line

Select an environment

Choose an environment to view and manage identities. @@ -28,7 +28,7 @@ diff --git a/src/admin/tests/__mocks__/fileMock.js b/src/admin/tests/__mocks__/fileMock.js old mode 100644 new mode 100755 diff --git a/src/admin/tests/__mocks__/styleMock.js b/src/admin/tests/__mocks__/styleMock.js old mode 100644 new mode 100755 diff --git a/src/admin/tests/setup.ts b/src/admin/tests/setup.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/AppHeader.spec.ts b/src/admin/tests/unit/AppHeader.spec.ts deleted file mode 100644 index 8f2502d..0000000 --- a/src/admin/tests/unit/AppHeader.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { describe, it, expect, beforeEach } from '@jest/globals'; -import { mount, VueWrapper } from '@vue/test-utils'; -import { createRouter, createMemoryHistory } from 'vue-router'; -import AppHeader from '@/components/AppHeader.vue'; - -function makeRouter() { - return createRouter({ - history: createMemoryHistory(), - routes: [ - { path: '/', component: { template: '

' } }, - { path: '/profile', component: { template: '
' } }, - { path: '/settings', component: { template: '
' } }, - ], - }); -} - -describe('AppHeader', () => { - let wrapper: VueWrapper; - - beforeEach(async () => { - const router = makeRouter(); - await router.push('/'); - - wrapper = mount( - { template: '', components: { AppHeader } }, - { global: { plugins: [router] } }, - ); - }); - - it('renders the SVG microphone logo image', () => { - const logo = wrapper.find('[data-testid="app-logo"]'); - expect(logo.exists()).toBe(true); - expect(logo.attributes('alt')).toBe('MicCheck logo'); - }); - - it('renders the profile link', () => { - const link = wrapper.find('[data-testid="profile-link"]'); - expect(link.exists()).toBe(true); - }); - - it('renders the settings gear icon link', () => { - const link = wrapper.find('[data-testid="settings-link"]'); - expect(link.exists()).toBe(true); - }); -}); diff --git a/src/admin/tests/unit/api/client.spec.ts b/src/admin/tests/unit/api/client.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/components/EnvironmentTabBar.spec.ts b/src/admin/tests/unit/components/EnvironmentTabBar.spec.ts old mode 100644 new mode 100755 index e2f3272..68e99c2 --- a/src/admin/tests/unit/components/EnvironmentTabBar.spec.ts +++ b/src/admin/tests/unit/components/EnvironmentTabBar.spec.ts @@ -56,13 +56,6 @@ describe('EnvironmentTabBar', () => { expect(envApi.listEnvironments).not.toHaveBeenCalled(); }); - it('ThenNoProjectMessageIsShown', async () => { - const wrapper = mountComponent(); - await flushPromises(); - - expect(wrapper.find('[data-testid="env-no-project-message"]').exists()).toBe(true); - }); - it('ThenCreateEnvironmentButtonIsDisabled', async () => { const wrapper = mountComponent(); await flushPromises(); @@ -84,7 +77,7 @@ describe('EnvironmentTabBar', () => { expect(envApi.listEnvironments).toHaveBeenCalledWith(mockProject.id); }); - it('ThenEnvironmentChipsAreRendered', async () => { + it('ThenEnvironmentSelectIsEnabled', async () => { jest.mocked(envApi.listEnvironments).mockResolvedValue(mockEnvironments); const contextStore = useContextStore(); @@ -93,8 +86,7 @@ describe('EnvironmentTabBar', () => { contextStore.setProject(mockProject); await flushPromises(); - expect(wrapper.find('[data-testid="env-chip-development"]').exists()).toBe(true); - expect(wrapper.find('[data-testid="env-chip-production"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="env-select"]').attributes('disabled')).toBeUndefined(); }); it('ThenFirstEnvironmentIsAutoSelected', async () => { @@ -122,7 +114,7 @@ describe('EnvironmentTabBar', () => { }); }); - describe('WhenEnvironmentChipIsClicked', () => { + describe('WhenEnvironmentIsSelected', () => { it('ThenContextStoreIsUpdatedWithSelectedEnvironment', async () => { jest.mocked(envApi.listEnvironments).mockResolvedValue(mockEnvironments); @@ -132,7 +124,7 @@ describe('EnvironmentTabBar', () => { contextStore.setProject(mockProject); await flushPromises(); - await wrapper.findComponent({ name: 'VChipGroup' }).vm.$emit('update:modelValue', 1); + await wrapper.findComponent({ name: 'VSelect' }).vm.$emit('update:modelValue', mockEnvironments[1]); expect(contextStore.currentEnvironment).toEqual(mockEnvironments[1]); }); @@ -158,16 +150,49 @@ describe('EnvironmentTabBar', () => { }); describe('WhenApiReturnsNoEnvironments', () => { - it('ThenEmptyMessageIsDisplayed', async () => { + it('ThenNoEnvironmentIsAutoSelected', async () => { jest.mocked(envApi.listEnvironments).mockResolvedValue([]); const contextStore = useContextStore(); - const wrapper = mountComponent(); + mountComponent(); contextStore.setProject(mockProject); await flushPromises(); - expect(wrapper.find('[data-testid="env-empty-message"]').exists()).toBe(true); + expect(contextStore.currentEnvironment).toBeNull(); + }); + }); + + describe('WhenStoredEnvironmentExistsInContextStore', () => { + it('ThenStoredEnvironmentIsRestoredAfterFetch', async () => { + jest.mocked(envApi.listEnvironments).mockResolvedValue(mockEnvironments); + + const contextStore = useContextStore(); + contextStore.setProject(mockProject); + contextStore.setEnvironment(mockEnvironments[1]); + + mountComponent(); + await flushPromises(); + + expect(contextStore.currentEnvironment).toEqual(mockEnvironments[1]); + }); + + it('ThenEnvironmentIsClearedWhenProjectChanges', async () => { + jest.mocked(envApi.listEnvironments).mockResolvedValue(mockEnvironments); + + const contextStore = useContextStore(); + contextStore.setProject(mockProject); + contextStore.setEnvironment(mockEnvironments[0]); + + mountComponent(); + await flushPromises(); + + const newProject: ProjectResponse = { ...mockProject, id: 20, name: 'Mobile' }; + jest.mocked(envApi.listEnvironments).mockResolvedValue([]); + contextStore.setProject(newProject); + await flushPromises(); + + expect(contextStore.currentEnvironment).toBeNull(); }); }); diff --git a/src/admin/tests/unit/components/OrgSelector.spec.ts b/src/admin/tests/unit/components/OrgSelector.spec.ts old mode 100644 new mode 100755 index 32fe763..9288983 --- a/src/admin/tests/unit/components/OrgSelector.spec.ts +++ b/src/admin/tests/unit/components/OrgSelector.spec.ts @@ -18,8 +18,8 @@ import * as orgsApi from '@/api/organizations'; const dialogStub = { template: '
' }; const mockOrgs: OrganizationResponse[] = [ - { id: 1, name: 'Acme Corp', createdAt: '2026-01-01T00:00:00Z' }, - { id: 2, name: 'Globex', createdAt: '2026-01-01T00:00:00Z' }, + { id: 1, name: 'Acme Corp', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }, + { id: 2, name: 'Globex', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }, ]; function mountComponent() { @@ -132,7 +132,7 @@ describe('OrgSelector', () => { }); describe('WhenCreateOrganizationIsConfirmed', () => { - const newOrg: OrganizationResponse = { id: 3, name: 'New Org', createdAt: '2026-04-13T00:00:00Z' }; + const newOrg: OrganizationResponse = { id: 3, name: 'New Org', createdAt: '2026-04-13T00:00:00Z', isPrimary: false }; it('ThenCreateOrganizationApiIsCalled', async () => { jest.mocked(orgsApi.listOrganizations).mockResolvedValue([]); diff --git a/src/admin/tests/unit/components/ProjectSelector.spec.ts b/src/admin/tests/unit/components/ProjectSelector.spec.ts old mode 100644 new mode 100755 index 06d8ce5..9011355 --- a/src/admin/tests/unit/components/ProjectSelector.spec.ts +++ b/src/admin/tests/unit/components/ProjectSelector.spec.ts @@ -17,7 +17,7 @@ import * as projectsApi from '@/api/projects'; const dialogStub = { template: '
' }; -const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z' }; +const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }; const mockProjects: ProjectResponse[] = [ { id: 10, name: 'Website', organizationId: 1, hideDisabledFlags: false, createdAt: '2026-01-01T00:00:00Z' }, { id: 11, name: 'Mobile App', organizationId: 1, hideDisabledFlags: false, createdAt: '2026-01-01T00:00:00Z' }, @@ -104,6 +104,54 @@ describe('ProjectSelector', () => { }); }); + describe('WhenStoredProjectExistsInContextStore', () => { + it('ThenStoredProjectIsRestoredAfterFetch', async () => { + jest.mocked(projectsApi.listProjects).mockResolvedValue(mockProjects); + + const contextStore = useContextStore(); + contextStore.setOrganization(mockOrg); + contextStore.setProject(mockProjects[1]); + + mountComponent(); + await flushPromises(); + + expect(contextStore.currentProject).toEqual(mockProjects[1]); + }); + + it('ThenProjectIsClearedWhenNotFoundInNewOrg', async () => { + jest.mocked(projectsApi.listProjects).mockResolvedValue(mockProjects); + + const contextStore = useContextStore(); + contextStore.setOrganization(mockOrg); + contextStore.setProject(mockProjects[0]); + + mountComponent(); + await flushPromises(); + + const newOrg: OrganizationResponse = { id: 2, name: 'Globex', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }; + jest.mocked(projectsApi.listProjects).mockResolvedValue([]); + contextStore.setOrganization(newOrg); + await flushPromises(); + + expect(contextStore.currentProject).toBeNull(); + }); + }); + + describe('WhenSingleProjectIsAvailable', () => { + it('ThenItIsAutoSelected', async () => { + const singleProject = mockProjects[0]; + jest.mocked(projectsApi.listProjects).mockResolvedValue([singleProject]); + + const contextStore = useContextStore(); + mountComponent(); + + contextStore.setOrganization(mockOrg); + await flushPromises(); + + expect(contextStore.currentProject).toEqual(singleProject); + }); + }); + describe('WhenOrganizationChanges', () => { it('ThenProjectsAreReloaded', async () => { jest.mocked(projectsApi.listProjects).mockResolvedValue(mockProjects); @@ -114,7 +162,7 @@ describe('ProjectSelector', () => { contextStore.setOrganization(mockOrg); await flushPromises(); - const newOrg: OrganizationResponse = { id: 2, name: 'Globex', createdAt: '2026-01-01T00:00:00Z' }; + const newOrg: OrganizationResponse = { id: 2, name: 'Globex', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }; contextStore.setOrganization(newOrg); await flushPromises(); diff --git a/src/admin/tests/unit/components/features/FeatureDetail.spec.ts b/src/admin/tests/unit/components/features/FeatureDetail.spec.ts old mode 100644 new mode 100755 index e7c917d..e63db83 --- a/src/admin/tests/unit/components/features/FeatureDetail.spec.ts +++ b/src/admin/tests/unit/components/features/FeatureDetail.spec.ts @@ -46,7 +46,7 @@ describe('FeatureDetail', () => { setActivePinia(createPinia()); jest.clearAllMocks(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment({ id: 100, name: 'Development', apiKey: 'env-dev', projectId: 10, createdAt: '' }); }); diff --git a/src/admin/tests/unit/components/features/FeatureDialog.spec.ts b/src/admin/tests/unit/components/features/FeatureDialog.spec.ts old mode 100644 new mode 100755 index 2305690..16edb46 --- a/src/admin/tests/unit/components/features/FeatureDialog.spec.ts +++ b/src/admin/tests/unit/components/features/FeatureDialog.spec.ts @@ -39,7 +39,7 @@ describe('FeatureDialog', () => { setActivePinia(createPinia()); jest.clearAllMocks(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); }); diff --git a/src/admin/tests/unit/components/features/TagsChipInput.spec.ts b/src/admin/tests/unit/components/features/TagsChipInput.spec.ts old mode 100644 new mode 100755 index 692d9df..f29a75d --- a/src/admin/tests/unit/components/features/TagsChipInput.spec.ts +++ b/src/admin/tests/unit/components/features/TagsChipInput.spec.ts @@ -1,12 +1,13 @@ import { describe, it, expect, beforeEach, jest } from '@jest/globals'; -import { mount, flushPromises, type VueWrapper } from '@vue/test-utils'; +import { mount, flushPromises, DOMWrapper, type VueWrapper } from '@vue/test-utils'; import { setActivePinia, createPinia } from 'pinia'; import { createRouter, createMemoryHistory } from 'vue-router'; import TagsChipInput from '@/components/features/TagsChipInput.vue'; import { useContextStore } from '@/stores/context'; -import type { ProjectResponse, TagResponse } from '@/types/api'; +import type { ProjectResponse, TagResponse, FeatureResponse } from '@/types/api'; jest.mock('@/api/tags'); +jest.mock('@/api/features'); jest.mock('@/api/client', () => ({ setAuthTokens: jest.fn(), clearAuthTokens: jest.fn(), @@ -14,18 +15,25 @@ jest.mock('@/api/client', () => ({ })); import * as tagsApi from '@/api/tags'; +import * as featuresApi from '@/api/features'; const mockProject: ProjectResponse = { id: 10, name: 'Website', organizationId: 1, hideDisabledFlags: false, createdAt: '2026-01-01T00:00:00Z', }; -const mockTags: TagResponse[] = [ - { id: 1, label: 'backend', color: '#ff0000', projectId: 10 }, - { id: 2, label: 'frontend', color: '#0000ff', projectId: 10 }, -]; +const backendTag: TagResponse = { id: 1, label: 'backend', color: '#ff0000', projectId: 10 }; +const frontendTag: TagResponse = { id: 2, label: 'frontend', color: '#0000ff', projectId: 10 }; +const mockTags: TagResponse[] = [backendTag, frontendTag]; -function mountComponent() { +function mockFeature(tags: TagResponse[]): FeatureResponse { + return { + id: 1, name: 'dark_mode', type: 'STANDARD', initialValue: null, description: null, + defaultEnabled: false, projectId: 10, createdAt: '2026-01-01T00:00:00Z', tags, + }; +} + +function mountComponent(feature: FeatureResponse) { const router = createRouter({ history: createMemoryHistory(), routes: [{ path: '/', component: { template: '
' } }] }); - return mount(TagsChipInput, { global: { plugins: [router] } }); + return mount(TagsChipInput, { props: { feature }, global: { plugins: [router] } }); } describe('TagsChipInput', () => { @@ -33,107 +41,180 @@ describe('TagsChipInput', () => { setActivePinia(createPinia()); jest.clearAllMocks(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); }); describe('WhenComponentMounts', () => { it('ThenTagsAreFetchedFromApi', async () => { jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); - mountComponent(); + mountComponent(mockFeature([])); await flushPromises(); expect(tagsApi.listTags).toHaveBeenCalledWith(mockProject.id); }); - it('ThenExistingTagChipsAreRendered', async () => { + it('ThenAssignedTagChipsAreRendered', async () => { jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); - const wrapper = mountComponent(); + const wrapper = mountComponent(mockFeature([backendTag])); await flushPromises(); expect(wrapper.find('[data-testid="tag-chip-backend"]').exists()).toBe(true); - expect(wrapper.find('[data-testid="tag-chip-frontend"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="tag-chip-frontend"]').exists()).toBe(false); }); - it('ThenEmptyMessageIsShownWhenNoTagsExist', async () => { - jest.mocked(tagsApi.listTags).mockResolvedValue([]); - const wrapper = mountComponent(); + it('ThenEmptyMessageIsShownWhenNoTagsAssigned', async () => { + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + const wrapper = mountComponent(mockFeature([])); await flushPromises(); expect(wrapper.find('[data-testid="tags-empty-message"]').exists()).toBe(true); }); }); - describe('WhenCreateTagIsSubmitted', () => { - it('ThenCreateTagApiIsCalled', async () => { + describe('WhenAddingANewTagName', () => { + it('ThenCreateTagAndAssignAreBothCalled', async () => { const newTag: TagResponse = { id: 3, label: 'api', color: '#00ff00', projectId: 10 }; + const updatedFeature = mockFeature([newTag]); jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); jest.mocked(tagsApi.createTag).mockResolvedValue(newTag); + jest.mocked(featuresApi.assignFeatureTag).mockResolvedValue(updatedFeature); - const wrapper = mountComponent(); + const wrapper = mountComponent(mockFeature([])); await flushPromises(); - // Open the create form - await wrapper.find('[data-testid="create-tag-btn"]').trigger('click'); - await wrapper.vm.$nextTick(); - - // Fill in the label - await (wrapper.findComponent('[data-testid="new-tag-label-input"]') as VueWrapper).vm.$emit('update:modelValue', 'api'); - - // Submit - await wrapper.find('[data-testid="confirm-create-tag-btn"]').trigger('click'); + const input = wrapper.findComponent('[data-testid="tag-name-input"]') as VueWrapper; + await input.vm.$emit('update:modelValue', 'api'); + await wrapper.find('[data-testid="add-tag-btn"]').trigger('click'); await flushPromises(); - expect(tagsApi.createTag).toHaveBeenCalledWith( - mockProject.id, - expect.objectContaining({ label: 'api' }), - ); + expect(tagsApi.createTag).toHaveBeenCalledWith(mockProject.id, expect.objectContaining({ label: 'api' })); + expect(featuresApi.assignFeatureTag).toHaveBeenCalledWith(mockProject.id, 1, newTag.id); }); - it('ThenNewTagAppearsInTheList', async () => { + it('ThenUpdatedEventIsEmitted', async () => { const newTag: TagResponse = { id: 3, label: 'api', color: '#00ff00', projectId: 10 }; - jest.mocked(tagsApi.listTags).mockResolvedValue([]); + const updatedFeature = mockFeature([newTag]); + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); jest.mocked(tagsApi.createTag).mockResolvedValue(newTag); + jest.mocked(featuresApi.assignFeatureTag).mockResolvedValue(updatedFeature); - const wrapper = mountComponent(); + const wrapper = mountComponent(mockFeature([])); await flushPromises(); - await wrapper.find('[data-testid="create-tag-btn"]').trigger('click'); - await wrapper.vm.$nextTick(); - await (wrapper.findComponent('[data-testid="new-tag-label-input"]') as VueWrapper).vm.$emit('update:modelValue', 'api'); - await wrapper.find('[data-testid="confirm-create-tag-btn"]').trigger('click'); + const input = wrapper.findComponent('[data-testid="tag-name-input"]') as VueWrapper; + await input.vm.$emit('update:modelValue', 'api'); + await wrapper.find('[data-testid="add-tag-btn"]').trigger('click'); await flushPromises(); - expect(wrapper.find('[data-testid="tag-chip-api"]').exists()).toBe(true); + expect(wrapper.emitted('updated')?.[0]).toEqual([updatedFeature]); }); }); - describe('WhenTagChipIsDeleted', () => { - it('ThenDeleteTagApiIsCalled', async () => { + describe('WhenTypedNameMatchesAnExistingTag', () => { + it('ThenExistingTagIsAssignedInsteadOfCreatingANewOne', async () => { + const updatedFeature = mockFeature([backendTag]); jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); - jest.mocked(tagsApi.deleteTag).mockResolvedValue(undefined); + jest.mocked(featuresApi.assignFeatureTag).mockResolvedValue(updatedFeature); - const wrapper = mountComponent(); + const wrapper = mountComponent(mockFeature([])); await flushPromises(); - const chip = wrapper.findComponent('[data-testid="tag-chip-backend"]') as VueWrapper; - await chip.vm.$emit('click:close'); + const input = wrapper.findComponent('[data-testid="tag-name-input"]') as VueWrapper; + await input.vm.$emit('update:modelValue', 'backend'); + await wrapper.find('[data-testid="add-tag-btn"]').trigger('click'); await flushPromises(); - expect(tagsApi.deleteTag).toHaveBeenCalledWith(mockProject.id, mockTags[0].id); + expect(tagsApi.createTag).not.toHaveBeenCalled(); + expect(featuresApi.assignFeatureTag).toHaveBeenCalledWith(mockProject.id, 1, backendTag.id); + }); + }); + + describe('WhenTypingTwoOrMoreCharacters', () => { + it('ThenMatchingUnassignedTagsAreSuggested', async () => { + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + + const wrapper = mountComponent(mockFeature([])); + await flushPromises(); + + const input = wrapper.findComponent('[data-testid="tag-name-input"]') as VueWrapper; + await input.vm.$emit('update:modelValue', 'ba'); + await wrapper.vm.$nextTick(); + + expect(input.props('items')).toEqual(['backend']); }); - it('ThenDeletedTagIsRemovedFromTheList', async () => { + it('ThenNoSuggestionsAreShownBelowTwoCharacters', async () => { jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); - jest.mocked(tagsApi.deleteTag).mockResolvedValue(undefined); - const wrapper = mountComponent(); + const wrapper = mountComponent(mockFeature([])); + await flushPromises(); + + const input = wrapper.findComponent('[data-testid="tag-name-input"]') as VueWrapper; + await input.vm.$emit('update:modelValue', 'b'); + await wrapper.vm.$nextTick(); + + expect(input.props('items')).toEqual([]); + }); + }); + + describe('WhenChoosingATagColour', () => { + it('ThenSwatchClickOpensTheColourDialog', async () => { + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + const wrapper = mountComponent(mockFeature([])); + await flushPromises(); + + expect(wrapper.find('[data-testid="color-dialog"]').exists()).toBe(false); + await wrapper.find('[data-testid="tag-color-swatch"]').trigger('click'); + await flushPromises(); + + expect(wrapper.findComponent({ name: 'VDialog' }).props('modelValue')).toBe(true); + }); + + it('ThenFifteenPresetColoursAreOffered', async () => { + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + const wrapper = mountComponent(mockFeature([])); + await flushPromises(); + + await wrapper.find('[data-testid="tag-color-swatch"]').trigger('click'); + await flushPromises(); + + const presets = new DOMWrapper(document.body).findAll('[data-testid^="preset-color-"]'); + const distinctColors = new Set(presets.map((p) => p.attributes('data-testid'))); + expect(distinctColors.size).toBe(15); + }); + + it('ThenSelectingAPresetUpdatesTheSwatchAndClosesTheDialog', async () => { + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + const wrapper = mountComponent(mockFeature([])); + await flushPromises(); + + await wrapper.find('[data-testid="tag-color-swatch"]').trigger('click'); + await flushPromises(); + + const presets = new DOMWrapper(document.body).findAll('[data-testid="preset-color-#4CAF50"]'); + await presets[presets.length - 1].trigger('click'); + await wrapper.vm.$nextTick(); + await flushPromises(); + + expect(wrapper.find('[data-testid="tag-color-swatch"]').attributes('style')).toContain('background: rgb(76, 175, 80)'); + }); + }); + + describe('WhenTagChipIsClosed', () => { + it('ThenRemoveFeatureTagApiIsCalled', async () => { + const updatedFeature = mockFeature([]); + jest.mocked(tagsApi.listTags).mockResolvedValue(mockTags); + jest.mocked(featuresApi.removeFeatureTag).mockResolvedValue(updatedFeature); + + const wrapper = mountComponent(mockFeature([backendTag])); await flushPromises(); const chip = wrapper.findComponent('[data-testid="tag-chip-backend"]') as VueWrapper; await chip.vm.$emit('click:close'); await flushPromises(); - expect(wrapper.find('[data-testid="tag-chip-backend"]').exists()).toBe(false); + expect(featuresApi.removeFeatureTag).toHaveBeenCalledWith(mockProject.id, 1, backendTag.id); + expect(wrapper.emitted('updated')?.[0]).toEqual([updatedFeature]); }); }); }); diff --git a/src/admin/tests/unit/components/identities/IdentityDetail.spec.ts b/src/admin/tests/unit/components/identities/IdentityDetail.spec.ts old mode 100644 new mode 100755 index 5598d59..fec0b82 --- a/src/admin/tests/unit/components/identities/IdentityDetail.spec.ts +++ b/src/admin/tests/unit/components/identities/IdentityDetail.spec.ts @@ -60,7 +60,7 @@ describe('IdentityDetail', () => { setActivePinia(createPinia()); jest.clearAllMocks(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); diff --git a/src/admin/tests/unit/components/segments/SegmentEditor.spec.ts b/src/admin/tests/unit/components/segments/SegmentEditor.spec.ts old mode 100644 new mode 100755 index 962e460..60e5acd --- a/src/admin/tests/unit/components/segments/SegmentEditor.spec.ts +++ b/src/admin/tests/unit/components/segments/SegmentEditor.spec.ts @@ -42,7 +42,7 @@ describe('SegmentEditor', () => { setActivePinia(createPinia()); jest.clearAllMocks(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); }); diff --git a/src/admin/tests/unit/components/settings/WebhookDeliveryHistory.spec.ts b/src/admin/tests/unit/components/settings/WebhookDeliveryHistory.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/components/settings/WebhookDialog.spec.ts b/src/admin/tests/unit/components/settings/WebhookDialog.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/components/settings/WebhooksPanel.spec.ts b/src/admin/tests/unit/components/settings/WebhooksPanel.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/router/router.spec.ts b/src/admin/tests/unit/router/router.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/stores/auth.spec.ts b/src/admin/tests/unit/stores/auth.spec.ts old mode 100644 new mode 100755 diff --git a/src/admin/tests/unit/stores/context.spec.ts b/src/admin/tests/unit/stores/context.spec.ts old mode 100644 new mode 100755 index b0ef8a0..04ab3fa --- a/src/admin/tests/unit/stores/context.spec.ts +++ b/src/admin/tests/unit/stores/context.spec.ts @@ -3,7 +3,7 @@ import { setActivePinia, createPinia } from 'pinia'; import { useContextStore } from '@/stores/context'; import type { OrganizationResponse, ProjectResponse, EnvironmentResponse } from '@/types/api'; -const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z' }; +const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }; const mockProject: ProjectResponse = { id: 10, name: 'Website', @@ -119,6 +119,57 @@ describe('useContextStore', () => { }); }); + describe('WhenRefreshOrganizationIsCalled', () => { + it('ThenOrgIsUpdatedWithoutClearingProjectOrEnvironment', () => { + const store = useContextStore(); + store.setOrganization(mockOrg); + store.setProject(mockProject); + store.setEnvironment(mockEnv); + + const updatedOrg = { ...mockOrg, name: 'Acme Updated' }; + store.refreshOrganization(updatedOrg); + + expect(store.currentOrganization).toEqual(updatedOrg); + expect(store.currentProject).toEqual(mockProject); + expect(store.currentEnvironment).toEqual(mockEnv); + }); + + it('ThenOrgIsPersistedToLocalStorage', () => { + const store = useContextStore(); + const updatedOrg = { ...mockOrg, name: 'Acme Updated' }; + store.refreshOrganization(updatedOrg); + + const stored = JSON.parse(localStorage.getItem('mic_ctx_organization')!); + expect(stored).toEqual(updatedOrg); + }); + }); + + describe('WhenRefreshProjectIsCalled', () => { + it('ThenProjectIsUpdatedWithoutClearingEnvironment', () => { + const store = useContextStore(); + store.setProject(mockProject); + store.setEnvironment(mockEnv); + + const updatedProject = { ...mockProject, name: 'Website Updated' }; + store.refreshProject(updatedProject); + + expect(store.currentProject).toEqual(updatedProject); + expect(store.currentEnvironment).toEqual(mockEnv); + }); + }); + + describe('WhenRefreshEnvironmentIsCalled', () => { + it('ThenEnvironmentIsUpdatedAndPersisted', () => { + const store = useContextStore(); + const updatedEnv = { ...mockEnv, name: 'Production Updated' }; + store.refreshEnvironment(updatedEnv); + + expect(store.currentEnvironment).toEqual(updatedEnv); + const stored = JSON.parse(localStorage.getItem('mic_ctx_environment')!); + expect(stored).toEqual(updatedEnv); + }); + }); + describe('WhenClearContextIsCalled', () => { it('ThenAllContextIsRemovedFromStateAndStorage', () => { const store = useContextStore(); diff --git a/src/admin/tests/unit/views/AuditLogsView.spec.ts b/src/admin/tests/unit/views/AuditLogsView.spec.ts old mode 100644 new mode 100755 index e98e7e8..d9ce88a --- a/src/admin/tests/unit/views/AuditLogsView.spec.ts +++ b/src/admin/tests/unit/views/AuditLogsView.spec.ts @@ -23,12 +23,12 @@ const mockLogs: AuditLogResponse[] = [ { id: 1, resourceType: 'Feature', resourceId: '42', action: 'Created', changes: null, organizationId: 1, projectId: 10, environmentId: null, - actorUserId: 5, createdAt: '2026-01-10T10:00:00Z', + actorUserId: 5, actorUserName: 'Alice', createdAt: '2026-01-10T10:00:00Z', }, { id: 2, resourceType: 'FeatureState', resourceId: '99', action: 'Updated', changes: '{"enabled":true}', organizationId: 1, projectId: 10, environmentId: 100, - actorUserId: 5, createdAt: '2026-01-11T11:00:00Z', + actorUserId: 5, actorUserName: 'Alice', createdAt: '2026-01-11T11:00:00Z', }, ]; @@ -58,7 +58,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); mountView(); @@ -76,7 +76,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -95,7 +95,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -120,7 +120,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -145,7 +145,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -170,7 +170,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -195,7 +195,7 @@ describe('AuditLogsView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); diff --git a/src/admin/tests/unit/views/FeaturesView.spec.ts b/src/admin/tests/unit/views/FeaturesView.spec.ts old mode 100644 new mode 100755 index 246e000..b420ed2 --- a/src/admin/tests/unit/views/FeaturesView.spec.ts +++ b/src/admin/tests/unit/views/FeaturesView.spec.ts @@ -4,7 +4,7 @@ import { setActivePinia, createPinia } from 'pinia'; import { createRouter, createMemoryHistory } from 'vue-router'; import FeaturesView from '@/views/FeaturesView.vue'; import { useContextStore } from '@/stores/context'; -import type { ProjectResponse, EnvironmentResponse, FeatureResponse, FeatureStateResponse } from '@/types/api'; +import type { ProjectResponse, EnvironmentResponse, FeatureResponse, FeatureStateResponse, TagResponse } from '@/types/api'; jest.mock('@/api/features'); jest.mock('@/api/featureStates'); @@ -25,9 +25,13 @@ const mockEnv: EnvironmentResponse = { id: 100, name: 'Development', apiKey: 'env-dev', projectId: 10, createdAt: '2026-01-01T00:00:00Z', }; const mockFeatures: FeatureResponse[] = [ - { id: 1, name: 'dark_mode', type: 'STANDARD', initialValue: null, description: 'Dark mode toggle', defaultEnabled: false, projectId: 10, createdAt: '2026-01-01T00:00:00Z' }, - { id: 2, name: 'new_checkout', type: 'STANDARD', initialValue: null, description: null, defaultEnabled: true, projectId: 10, createdAt: '2026-01-01T00:00:00Z' }, + { id: 1, name: 'dark_mode', type: 'STANDARD', initialValue: null, description: 'Dark mode toggle', defaultEnabled: false, projectId: 10, createdAt: '2026-01-01T00:00:00Z', tags: [] }, + { id: 2, name: 'new_checkout', type: 'STANDARD', initialValue: null, description: null, defaultEnabled: true, projectId: 10, createdAt: '2026-01-01T00:00:00Z', tags: [] }, ]; + +function makeTag(id: number, label: string): TagResponse { + return { id, label, color: '#1565C0', projectId: 10, createdAt: '2026-01-01T00:00:00Z' }; +} const mockStates: FeatureStateResponse[] = [ { id: 101, featureId: 1, environmentId: 100, identityId: null, featureSegmentId: null, enabled: false, value: null, createdAt: '2026-01-01T00:00:00Z', updatedAt: '2026-01-01T00:00:00Z' }, { id: 102, featureId: 2, environmentId: 100, identityId: null, featureSegmentId: null, enabled: true, value: null, createdAt: '2026-01-01T00:00:00Z', updatedAt: '2026-01-01T00:00:00Z' }, @@ -58,7 +62,7 @@ describe('FeaturesView', () => { jest.mocked(featureStatesApi.listFeatureStates).mockResolvedValue(mockStates); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -74,7 +78,7 @@ describe('FeaturesView', () => { jest.mocked(featureStatesApi.listFeatureStates).mockResolvedValue(mockStates); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -85,6 +89,43 @@ describe('FeaturesView', () => { }); }); + describe('WhenFeatureHasTags', () => { + it('ThenUpToFiveTagChipsAreShownAndExtraAreEllipsised', async () => { + const sixTags = [1, 2, 3, 4, 5, 6].map((id) => makeTag(id, `tag-${id}`)); + const taggedFeature: FeatureResponse = { ...mockFeatures[0], tags: sixTags }; + jest.mocked(featuresApi.listFeatures).mockResolvedValue({ count: 1, next: null, previous: null, results: [taggedFeature] }); + jest.mocked(featureStatesApi.listFeatureStates).mockResolvedValue([]); + + const contextStore = useContextStore(); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); + contextStore.setProject(mockProject); + + const wrapper = mountView(); + await flushPromises(); + + const chips = sixTags.slice(0, 5).map((tag) => wrapper.find(`[data-testid="feature-tag-chip-${taggedFeature.id}-${tag.id}"]`)); + chips.forEach((chip) => expect(chip.exists()).toBe(true)); + expect(wrapper.find(`[data-testid="feature-tag-chip-${taggedFeature.id}-6"]`).exists()).toBe(false); + expect(wrapper.text()).toContain('…'); + }); + + it('ThenMissingTagsDoesNotThrow', async () => { + const untaggedFeature = { ...mockFeatures[0], tags: undefined } as unknown as FeatureResponse; + jest.mocked(featuresApi.listFeatures).mockResolvedValue({ count: 1, next: null, previous: null, results: [untaggedFeature] }); + jest.mocked(featureStatesApi.listFeatureStates).mockResolvedValue([]); + + const contextStore = useContextStore(); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); + contextStore.setProject(mockProject); + + const wrapper = mountView(); + await flushPromises(); + + expect(wrapper.find('[data-testid="features-table"]').exists()).toBe(true); + expect(wrapper.text()).toContain(untaggedFeature.name); + }); + }); + describe('WhenToggleEnabledIsClicked', () => { it('ThenPatchFeatureStateIsCalled', async () => { jest.mocked(featuresApi.listFeatures).mockResolvedValue({ count: 2, next: null, previous: null, results: mockFeatures }); @@ -92,7 +133,7 @@ describe('FeaturesView', () => { jest.mocked(featureStatesApi.patchFeatureState).mockResolvedValue({ ...mockStates[0], enabled: true }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -115,7 +156,7 @@ describe('FeaturesView', () => { jest.mocked(featureStatesApi.listFeatureStates).mockResolvedValue([]); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); diff --git a/src/admin/tests/unit/views/IdentitiesView.spec.ts b/src/admin/tests/unit/views/IdentitiesView.spec.ts old mode 100644 new mode 100755 index 4e41a1e..365fdab --- a/src/admin/tests/unit/views/IdentitiesView.spec.ts +++ b/src/admin/tests/unit/views/IdentitiesView.spec.ts @@ -57,7 +57,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -73,7 +73,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -91,7 +91,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -115,7 +115,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -137,7 +137,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); @@ -163,7 +163,7 @@ describe('IdentitiesView', () => { }); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); contextStore.setEnvironment(mockEnv); diff --git a/src/admin/tests/unit/views/ProfileView.spec.ts b/src/admin/tests/unit/views/ProfileView.spec.ts old mode 100644 new mode 100755 index 60a722a..f274349 --- a/src/admin/tests/unit/views/ProfileView.spec.ts +++ b/src/admin/tests/unit/views/ProfileView.spec.ts @@ -44,7 +44,7 @@ describe('ProfileView', () => { it('ThenOrgNameIsDisplayedWhenSelected', () => { const { wrapper } = mountView(); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme Corp', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme Corp', createdAt: '', isPrimary: false }); expect(wrapper.find('[data-testid="profile-org-name"]').exists()).toBe(false); // org name shown in v-if block }); diff --git a/src/admin/tests/unit/views/SegmentsView.spec.ts b/src/admin/tests/unit/views/SegmentsView.spec.ts old mode 100644 new mode 100755 index 3ed7f34..06d5cb4 --- a/src/admin/tests/unit/views/SegmentsView.spec.ts +++ b/src/admin/tests/unit/views/SegmentsView.spec.ts @@ -61,7 +61,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue(mockSegments); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); mountView(); @@ -74,7 +74,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue(mockSegments); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -88,7 +88,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue(mockSegments); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -104,7 +104,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue([]); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -123,7 +123,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue(mockSegments); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -143,7 +143,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.deleteSegment).mockResolvedValue(undefined); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -172,7 +172,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.deleteSegment).mockResolvedValue(undefined); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -196,7 +196,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue([]); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); @@ -214,7 +214,7 @@ describe('SegmentsView', () => { jest.mocked(segmentsApi.listSegments).mockResolvedValue([...mockSegments]); const contextStore = useContextStore(); - contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '' }); + contextStore.setOrganization({ id: 1, name: 'Acme', createdAt: '', isPrimary: false }); contextStore.setProject(mockProject); const wrapper = mountView(); diff --git a/src/admin/tests/unit/views/SettingsView.spec.ts b/src/admin/tests/unit/views/SettingsView.spec.ts old mode 100644 new mode 100755 index 7511abb..4d19021 --- a/src/admin/tests/unit/views/SettingsView.spec.ts +++ b/src/admin/tests/unit/views/SettingsView.spec.ts @@ -26,7 +26,7 @@ import * as environmentsApi from '@/api/environments'; import * as apiKeysApi from '@/api/apiKeys'; import * as webhooksApi from '@/api/webhooks'; -const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z' }; +const mockOrg: OrganizationResponse = { id: 1, name: 'Acme', createdAt: '2026-01-01T00:00:00Z', isPrimary: false }; const mockProject: ProjectResponse = { id: 10, name: 'Website', organizationId: 1, hideDisabledFlags: false, createdAt: '2026-01-01T00:00:00Z' }; const mockEnvs: EnvironmentResponse[] = [ { id: 100, name: 'Development', apiKey: 'env-dev', projectId: 10, createdAt: '2026-01-01T00:00:00Z' }, diff --git a/src/admin/tsconfig.json b/src/admin/tsconfig.json old mode 100644 new mode 100755 index 4999642..33a3750 --- a/src/admin/tsconfig.json +++ b/src/admin/tsconfig.json @@ -15,15 +15,23 @@ "resolveJsonModule": true, "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": ["src/*"], + "@core/*": ["src/@core/*"], + "@core": ["src/@core"], + "@layouts/*": ["src/@layouts/*"], + "@layouts": ["src/@layouts"], + "@images/*": ["src/assets/images/*"], + "@styles/*": ["src/assets/styles/*"], + "@configured-variables": ["src/assets/styles/variables/_template.scss"] }, - "types": ["node", "jest"] + "types": ["node", "jest", "vite/client"] }, "include": [ "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", - "tests/**/*.ts" + "tests/**/*.ts", + "vite.config.ts" ], "exclude": [ "node_modules", diff --git a/src/admin/vite.config.ts b/src/admin/vite.config.ts old mode 100644 new mode 100755 index 2a46f76..e2f9a0a --- a/src/admin/vite.config.ts +++ b/src/admin/vite.config.ts @@ -1,19 +1,51 @@ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import vuetify from 'vite-plugin-vuetify'; +import svgLoader from 'vite-svg-loader'; import { fileURLToPath, URL } from 'node:url'; export default defineConfig({ plugins: [ vue(), - vuetify({ autoImport: true }), + vuetify({ + styles: { + configFile: 'src/assets/styles/variables/_vuetify.scss', + }, + }), + svgLoader(), ], + css: { + preprocessorOptions: { + scss: { + silenceDeprecations: ['if-function'], + }, + }, + }, + define: { 'process.env': {} }, + server: { + proxy: { + '/api': { + target: + process.env.services__api__https__0 ?? + process.env.services__api__http__0 ?? + 'http://localhost:5000', + changeOrigin: true, + secure: false, + }, + }, + }, resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), + '@core': fileURLToPath(new URL('./src/@core', import.meta.url)), + '@layouts': fileURLToPath(new URL('./src/@layouts', import.meta.url)), + '@images': fileURLToPath(new URL('./src/assets/images/', import.meta.url)), + '@styles': fileURLToPath(new URL('./src/assets/styles/', import.meta.url)), + '@configured-variables': fileURLToPath(new URL('./src/assets/styles/variables/_template.scss', import.meta.url)), }, }, build: { + chunkSizeWarningLimit: 5000, outDir: 'dist', rollupOptions: { output: { @@ -27,4 +59,8 @@ export default defineConfig({ }, }, }, + optimizeDeps: { + exclude: ['vuetify'], + entries: ['./src/**/*.vue'], + }, }); diff --git a/src/api/MicCheck.Api/Audit/AuditLog.cs b/src/api/MicCheck.Api/Audit/AuditLog.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Audit/AuditLogFilter.cs b/src/api/MicCheck.Api/Audit/AuditLogFilter.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Audit/AuditLogQueryService.cs b/src/api/MicCheck.Api/Audit/AuditLogQueryService.cs old mode 100644 new mode 100755 index 2078683..aa480a6 --- a/src/api/MicCheck.Api/Audit/AuditLogQueryService.cs +++ b/src/api/MicCheck.Api/Audit/AuditLogQueryService.cs @@ -5,28 +5,28 @@ namespace MicCheck.Api.Audit; public class AuditLogQueryService(MicCheckDbContext db) { - public async Task<(int Total, IReadOnlyList Items)> ListByOrganizationAsync( + public async Task<(int Total, IReadOnlyList Items)> ListByOrganizationAsync( int organizationId, AuditLogFilter filter, CancellationToken ct = default) { var query = db.AuditLogs.Where(l => l.OrganizationId == organizationId); return await ApplyFilterAndPageAsync(query, filter, ct); } - public async Task<(int Total, IReadOnlyList Items)> ListByProjectAsync( + public async Task<(int Total, IReadOnlyList Items)> ListByProjectAsync( int projectId, AuditLogFilter filter, CancellationToken ct = default) { var query = db.AuditLogs.Where(l => l.ProjectId == projectId); return await ApplyFilterAndPageAsync(query, filter, ct); } - public async Task<(int Total, IReadOnlyList Items)> ListByEnvironmentAsync( + public async Task<(int Total, IReadOnlyList Items)> ListByEnvironmentAsync( int environmentId, AuditLogFilter filter, CancellationToken ct = default) { var query = db.AuditLogs.Where(l => l.EnvironmentId == environmentId); return await ApplyFilterAndPageAsync(query, filter, ct); } - private static async Task<(int Total, IReadOnlyList Items)> ApplyFilterAndPageAsync( + private async Task<(int Total, IReadOnlyList Items)> ApplyFilterAndPageAsync( IQueryable query, AuditLogFilter filter, CancellationToken ct) { if (filter.From.HasValue) @@ -46,10 +46,21 @@ public class AuditLogQueryService(MicCheckDbContext db) var total = await query.CountAsync(ct); var pageSize = Math.Clamp(filter.PageSize, 1, 100); + var items = await query .OrderByDescending(l => l.CreatedAt) .Skip((filter.Page - 1) * pageSize) .Take(pageSize) + .GroupJoin( + db.Users, + log => log.ActorUserId, + user => (int?)user.Id, + (log, users) => new { log, users }) + .SelectMany( + x => x.users.DefaultIfEmpty(), + (x, user) => AuditLogResponse.From( + x.log, + user != null ? user.FirstName + " " + user.LastName : null)) .ToListAsync(ct); return (total, items); diff --git a/src/api/MicCheck.Api/Audit/AuditLogResponse.cs b/src/api/MicCheck.Api/Audit/AuditLogResponse.cs old mode 100644 new mode 100755 index 3f89e9b..c9154b5 --- a/src/api/MicCheck.Api/Audit/AuditLogResponse.cs +++ b/src/api/MicCheck.Api/Audit/AuditLogResponse.cs @@ -10,10 +10,11 @@ public record AuditLogResponse( int? ProjectId, int? EnvironmentId, int? ActorUserId, + string? ActorUserName, DateTimeOffset CreatedAt ) { - public static AuditLogResponse From(AuditLog log) => new( + public static AuditLogResponse From(AuditLog log, string? actorUserName = null) => new( log.Id, log.ResourceType, log.ResourceId, @@ -23,5 +24,6 @@ public record AuditLogResponse( log.ProjectId, log.EnvironmentId, log.ActorUserId, + actorUserName, log.CreatedAt); } diff --git a/src/api/MicCheck.Api/Audit/AuditLogsController.cs b/src/api/MicCheck.Api/Audit/AuditLogsController.cs old mode 100644 new mode 100755 index 348f199..fd760e7 --- a/src/api/MicCheck.Api/Audit/AuditLogsController.cs +++ b/src/api/MicCheck.Api/Audit/AuditLogsController.cs @@ -1,59 +1,59 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using MicCheck.Api.Environments; -using MicCheck.Api.Projects; -using MicCheck.Api.Organizations; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Audit; - -[ApiController] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class AuditLogsController( - AuditLogQueryService auditLogQueryService, - OrganizationService organizationService, - ProjectService projectService, - EnvironmentService environmentService) : ControllerBase -{ - [HttpGet("api/v1/organisations/{id}/audit-logs")] - public async Task>> ListByOrganization( - int id, - [FromQuery] AuditLogFilter filter, - CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var (total, logs) = await auditLogQueryService.ListByOrganizationAsync(id, filter, ct); - return Ok(new PaginatedResponse(total, null, null, logs.Select(AuditLogResponse.From).ToList())); - } - - [HttpGet("api/v1/projects/{projectId}/audit-logs")] - public async Task>> ListByProject( - int projectId, - [FromQuery] AuditLogFilter filter, - CancellationToken ct) - { - var project = await projectService.FindByIdAsync(projectId, ct); - if (project is null) return NotFound(); - - var (total, logs) = await auditLogQueryService.ListByProjectAsync(projectId, filter, ct); - return Ok(new PaginatedResponse(total, null, null, logs.Select(AuditLogResponse.From).ToList())); - } - - [HttpGet("api/v1/environments/{apiKey}/audit-logs")] - public async Task>> ListByEnvironment( - string apiKey, - [FromQuery] AuditLogFilter filter, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var (total, logs) = await auditLogQueryService.ListByEnvironmentAsync(environment.Id, filter, ct); - return Ok(new PaginatedResponse(total, null, null, logs.Select(AuditLogResponse.From).ToList())); - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using MicCheck.Api.Environments; +using MicCheck.Api.Projects; +using MicCheck.Api.Organizations; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Audit; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class AuditLogsController( + AuditLogQueryService auditLogQueryService, + OrganizationService organizationService, + ProjectService projectService, + EnvironmentService environmentService) : ControllerBase +{ + [HttpGet("api/v1/organisation/{id}/audit-logs")] + public async Task>> ListByOrganization( + int id, + [FromQuery] AuditLogFilter filter, + CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var (total, logs) = await auditLogQueryService.ListByOrganizationAsync(id, filter, ct); + return Ok(new PaginatedResponse(total, null, null, logs.ToList())); + } + + [HttpGet("api/v1/project/{projectId}/audit-logs")] + public async Task>> ListByProject( + int projectId, + [FromQuery] AuditLogFilter filter, + CancellationToken ct) + { + var project = await projectService.FindByIdAsync(projectId, ct); + if (project is null) return NotFound(); + + var (total, logs) = await auditLogQueryService.ListByProjectAsync(projectId, filter, ct); + return Ok(new PaginatedResponse(total, null, null, logs.ToList())); + } + + [HttpGet("api/v1/environment/{apiKey}/audit-logs")] + public async Task>> ListByEnvironment( + string apiKey, + [FromQuery] AuditLogFilter filter, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var (total, logs) = await auditLogQueryService.ListByEnvironmentAsync(environment.Id, filter, ct); + return Ok(new PaginatedResponse(total, null, null, logs.ToList())); + } +} diff --git a/src/api/MicCheck.Api/Audit/AuditService.cs b/src/api/MicCheck.Api/Audit/AuditService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Authorization/ITokenService.cs b/src/api/MicCheck.Api/Authorization/ITokenService.cs deleted file mode 100644 index bbbfba1..0000000 --- a/src/api/MicCheck.Api/Authorization/ITokenService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MicCheck.Api.Users; - -namespace MicCheck.Api.Authorization; - -public interface ITokenService -{ - TokenResponse GenerateToken(User user); -} diff --git a/src/api/MicCheck.Api/Authorization/LogoutRequest.cs b/src/api/MicCheck.Api/Authorization/LogoutRequest.cs deleted file mode 100644 index b379da0..0000000 --- a/src/api/MicCheck.Api/Authorization/LogoutRequest.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MicCheck.Api.Authorization; - -public record LogoutRequest(string Token); diff --git a/src/api/MicCheck.Api/Authorization/RefreshRequest.cs b/src/api/MicCheck.Api/Authorization/RefreshRequest.cs deleted file mode 100644 index 94aa24e..0000000 --- a/src/api/MicCheck.Api/Authorization/RefreshRequest.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MicCheck.Api.Authorization; - -public record RefreshRequest(string Token); diff --git a/src/api/MicCheck.Api/Common/DomainException.cs b/src/api/MicCheck.Api/Common/DomainException.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Common/PaginatedResponse.cs b/src/api/MicCheck.Api/Common/PaginatedResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/ApiKeys/ApiKey.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKey.cs old mode 100644 new mode 100755 similarity index 86% rename from src/api/MicCheck.Api/ApiKeys/ApiKey.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKey.cs index c3319e0..8a7df52 --- a/src/api/MicCheck.Api/ApiKeys/ApiKey.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKey.cs @@ -1,13 +1,13 @@ -namespace MicCheck.Api.ApiKeys; - -public class ApiKey -{ - public int Id { get; init; } - public required string Key { get; set; } - public required string Prefix { get; set; } - public required string Name { get; set; } - public int OrganizationId { get; init; } - public bool IsActive { get; set; } - public DateTimeOffset? ExpiresAt { get; set; } - public DateTimeOffset CreatedAt { get; init; } -} +namespace MicCheck.Api.Common.Security.ApiKeys; + +public class ApiKey +{ + public int Id { get; init; } + public required string Key { get; set; } + public required string Prefix { get; set; } + public required string Name { get; set; } + public int OrganizationId { get; init; } + public bool IsActive { get; set; } + public DateTimeOffset? ExpiresAt { get; set; } + public DateTimeOffset CreatedAt { get; init; } +} diff --git a/src/api/MicCheck.Api/ApiKeys/ApiKeyEndpoints.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyEndpoints.cs old mode 100644 new mode 100755 similarity index 50% rename from src/api/MicCheck.Api/ApiKeys/ApiKeyEndpoints.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyEndpoints.cs index ca100f9..e5dd6ae --- a/src/api/MicCheck.Api/ApiKeys/ApiKeyEndpoints.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyEndpoints.cs @@ -1,46 +1,37 @@ -using MicCheck.Api.Authorization; - -namespace MicCheck.Api.ApiKeys; - -public static class ApiKeyEndpoints -{ - public static void MapApiKeyEndpoints(this WebApplication app) - { - var group = app - .MapGroup("/api/v1/organisations/{organizationId:int}/api-keys") - .RequireAuthorization(AuthorizationPolicies.OrganizationAdmin) - .WithTags("ApiKeys"); - - group.MapPost("/", async ( - int organizationId, - CreateApiKeyRequest request, - ApiKeyService apiKeyService, - CancellationToken ct) => - { - var (key, rawKey) = await apiKeyService.CreateAsync( - organizationId, request.Name, request.ExpiresAt, ct); - - return Results.Ok(new CreateApiKeyResponse(key.Id, key.Name, rawKey, key.Prefix, key.ExpiresAt)); - }).WithName("CreateApiKey"); - - group.MapGet("/", async ( - int organizationId, - ApiKeyService apiKeyService, - CancellationToken ct) => - { - var keys = await apiKeyService.ListAsync(organizationId, ct); - return Results.Ok(keys.Select(k => - new ApiKeyResponse(k.Id, k.Name, k.Prefix, k.IsActive, k.ExpiresAt, k.CreatedAt))); - }).WithName("ListApiKeys"); - - group.MapDelete("/{keyId:int}", async ( - int organizationId, - int keyId, - ApiKeyService apiKeyService, - CancellationToken ct) => - { - await apiKeyService.RevokeAsync(organizationId, keyId, ct); - return Results.NoContent(); - }).WithName("RevokeApiKey"); - } -} +using MicCheck.Api.Common.Security.Authorization; + +namespace MicCheck.Api.Common.Security.ApiKeys; + +public static class ApiKeyEndpoints +{ + public static void MapApiKeyEndpoints(this WebApplication app) + { + var group = app + .MapGroup("/api/v1/organisation/{organizationId:int}") + .RequireAuthorization(AuthorizationPolicies.OrganizationAdmin) + .WithTags("ApiKeys"); + + group.MapPost("/api-keys", async (int organizationId, CreateApiKeyRequest request, ApiKeyService apiKeyService, CancellationToken ct) => + { + var (key, rawKey) = await apiKeyService.CreateAsync( + organizationId, request.Name, request.ExpiresAt, ct); + + return Results.Ok(new CreateApiKeyResponse(key.Id, key.Name, rawKey, key.Prefix, key.ExpiresAt)); + + }).WithName("CreateApiKey"); + + group.MapGet("/api-keys", async (int organizationId, ApiKeyService apiKeyService, CancellationToken ct) => + { + var keys = await apiKeyService.ListAsync(organizationId, ct); + return Results.Ok(keys.Select(k => new ApiKeyResponse(k.Id, k.Name, k.Prefix, k.IsActive, k.ExpiresAt, k.CreatedAt))); + + }).WithName("ListApiKeys"); + + group.MapDelete("/api-key/{keyId:int}", async (int organizationId, int keyId, ApiKeyService apiKeyService, CancellationToken ct) => + { + await apiKeyService.RevokeAsync(organizationId, keyId, ct); + return Results.NoContent(); + + }).WithName("RevokeApiKey"); + } +} diff --git a/src/api/MicCheck.Api/ApiKeys/ApiKeyHasher.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyHasher.cs old mode 100644 new mode 100755 similarity index 88% rename from src/api/MicCheck.Api/ApiKeys/ApiKeyHasher.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyHasher.cs index 63a7445..82459d3 --- a/src/api/MicCheck.Api/ApiKeys/ApiKeyHasher.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyHasher.cs @@ -1,22 +1,22 @@ -using System.Security.Cryptography; -using System.Text; - -namespace MicCheck.Api.ApiKeys; - -public static class ApiKeyHasher -{ - public static string Hash(string key) - { - var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(key)); - return Convert.ToHexString(bytes).ToLowerInvariant(); - } - - public static string GenerateKey() - { - var bytes = RandomNumberGenerator.GetBytes(32); - return Convert.ToBase64String(bytes) - .TrimEnd('=') - .Replace('+', '-') - .Replace('/', '_'); - } -} +using System.Security.Cryptography; +using System.Text; + +namespace MicCheck.Api.Common.Security.ApiKeys; + +public static class ApiKeyHasher +{ + public static string Hash(string key) + { + var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(key)); + return Convert.ToHexString(bytes).ToLowerInvariant(); + } + + public static string GenerateKey() + { + var bytes = RandomNumberGenerator.GetBytes(32); + return Convert.ToBase64String(bytes) + .TrimEnd('=') + .Replace('+', '-') + .Replace('/', '_'); + } +} diff --git a/src/api/MicCheck.Api/ApiKeys/ApiKeyResponse.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyResponse.cs old mode 100644 new mode 100755 similarity index 73% rename from src/api/MicCheck.Api/ApiKeys/ApiKeyResponse.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyResponse.cs index 98e32d5..3ffa955 --- a/src/api/MicCheck.Api/ApiKeys/ApiKeyResponse.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyResponse.cs @@ -1,9 +1,9 @@ -namespace MicCheck.Api.ApiKeys; - -public record ApiKeyResponse( - int Id, - string Name, - string Prefix, - bool IsActive, - DateTimeOffset? ExpiresAt, - DateTimeOffset CreatedAt); +namespace MicCheck.Api.Common.Security.ApiKeys; + +public record ApiKeyResponse( + int Id, + string Name, + string Prefix, + bool IsActive, + DateTimeOffset? ExpiresAt, + DateTimeOffset CreatedAt); diff --git a/src/api/MicCheck.Api/ApiKeys/ApiKeyService.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyService.cs old mode 100644 new mode 100755 similarity index 93% rename from src/api/MicCheck.Api/ApiKeys/ApiKeyService.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyService.cs index f697c5a..a343597 --- a/src/api/MicCheck.Api/ApiKeys/ApiKeyService.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/ApiKeyService.cs @@ -1,50 +1,50 @@ -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; - -namespace MicCheck.Api.ApiKeys; - -public class ApiKeyService(MicCheckDbContext db) -{ - public async Task<(ApiKey Key, string RawKey)> CreateAsync( - int organizationId, string name, DateTimeOffset? expiresAt, CancellationToken ct = default) - { - var rawKey = ApiKeyHasher.GenerateKey(); - var hashedKey = ApiKeyHasher.Hash(rawKey); - var prefix = rawKey.Length >= 8 ? rawKey[..8] : rawKey; - - var apiKey = new ApiKey - { - Key = hashedKey, - Prefix = prefix, - Name = name, - OrganizationId = organizationId, - IsActive = true, - ExpiresAt = expiresAt, - CreatedAt = DateTimeOffset.UtcNow - }; - - db.ApiKeys.Add(apiKey); - await db.SaveChangesAsync(ct); - - return (apiKey, rawKey); - } - - public async Task> ListAsync(int organizationId, CancellationToken ct = default) - { - return await db.ApiKeys - .Where(k => k.OrganizationId == organizationId) - .ToListAsync(ct); - } - - public async Task RevokeAsync(int organizationId, int keyId, CancellationToken ct = default) - { - var key = await db.ApiKeys - .FirstOrDefaultAsync(k => k.Id == keyId && k.OrganizationId == organizationId, ct); - - if (key is null) - return; - - key.IsActive = false; - await db.SaveChangesAsync(ct); - } -} +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Common.Security.ApiKeys; + +public class ApiKeyService(MicCheckDbContext db) +{ + public async Task<(ApiKey Key, string RawKey)> CreateAsync( + int organizationId, string name, DateTimeOffset? expiresAt, CancellationToken ct = default) + { + var rawKey = ApiKeyHasher.GenerateKey(); + var hashedKey = ApiKeyHasher.Hash(rawKey); + var prefix = rawKey.Length >= 8 ? rawKey[..8] : rawKey; + + var apiKey = new ApiKey + { + Key = hashedKey, + Prefix = prefix, + Name = name, + OrganizationId = organizationId, + IsActive = true, + ExpiresAt = expiresAt, + CreatedAt = DateTimeOffset.UtcNow + }; + + db.ApiKeys.Add(apiKey); + await db.SaveChangesAsync(ct); + + return (apiKey, rawKey); + } + + public async Task> ListAsync(int organizationId, CancellationToken ct = default) + { + return await db.ApiKeys + .Where(k => k.OrganizationId == organizationId) + .ToListAsync(ct); + } + + public async Task RevokeAsync(int organizationId, int keyId, CancellationToken ct = default) + { + var key = await db.ApiKeys + .FirstOrDefaultAsync(k => k.Id == keyId && k.OrganizationId == organizationId, ct); + + if (key is null) + return; + + key.IsActive = false; + await db.SaveChangesAsync(ct); + } +} diff --git a/src/api/MicCheck.Api/ApiKeys/CreateApiKeyRequest.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyRequest.cs old mode 100644 new mode 100755 similarity index 59% rename from src/api/MicCheck.Api/ApiKeys/CreateApiKeyRequest.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyRequest.cs index f495617..c629d00 --- a/src/api/MicCheck.Api/ApiKeys/CreateApiKeyRequest.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyRequest.cs @@ -1,3 +1,3 @@ -namespace MicCheck.Api.ApiKeys; - -public record CreateApiKeyRequest(string Name, DateTimeOffset? ExpiresAt); +namespace MicCheck.Api.Common.Security.ApiKeys; + +public record CreateApiKeyRequest(string Name, DateTimeOffset? ExpiresAt); diff --git a/src/api/MicCheck.Api/ApiKeys/CreateApiKeyResponse.cs b/src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyResponse.cs old mode 100644 new mode 100755 similarity index 70% rename from src/api/MicCheck.Api/ApiKeys/CreateApiKeyResponse.cs rename to src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyResponse.cs index 615ede6..89ad8e2 --- a/src/api/MicCheck.Api/ApiKeys/CreateApiKeyResponse.cs +++ b/src/api/MicCheck.Api/Common/Security/ApiKeys/CreateApiKeyResponse.cs @@ -1,8 +1,8 @@ -namespace MicCheck.Api.ApiKeys; - -public record CreateApiKeyResponse( - int Id, - string Name, - string Key, - string Prefix, - DateTimeOffset? ExpiresAt); +namespace MicCheck.Api.Common.Security.ApiKeys; + +public record CreateApiKeyResponse( + int Id, + string Name, + string Key, + string Prefix, + DateTimeOffset? ExpiresAt); diff --git a/src/api/MicCheck.Api/Authentication/ApiKeyAuthenticationHandler.cs b/src/api/MicCheck.Api/Common/Security/Authentication/ApiKeyAuthenticationHandler.cs old mode 100644 new mode 100755 similarity index 85% rename from src/api/MicCheck.Api/Authentication/ApiKeyAuthenticationHandler.cs rename to src/api/MicCheck.Api/Common/Security/Authentication/ApiKeyAuthenticationHandler.cs index 859bbe7..cae4780 --- a/src/api/MicCheck.Api/Authentication/ApiKeyAuthenticationHandler.cs +++ b/src/api/MicCheck.Api/Common/Security/Authentication/ApiKeyAuthenticationHandler.cs @@ -1,60 +1,56 @@ -using System.Security.Claims; -using System.Text.Encodings.Web; -using MicCheck.Api.ApiKeys; -using MicCheck.Api.Data; -using Microsoft.AspNetCore.Authentication; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; - -namespace MicCheck.Api.Authentication; - -public class ApiKeyAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - MicCheckDbContext db) - : AuthenticationHandler(options, logger, encoder) -{ - public const string SchemeName = "ApiKey"; - private const string ApiKeyPrefix = "Api-Key "; - - protected override async Task HandleAuthenticateAsync() - { - if (!Request.Headers.TryGetValue("Authorization", out var authHeader)) - return AuthenticateResult.NoResult(); - - var headerValue = authHeader.FirstOrDefault(); - if (string.IsNullOrWhiteSpace(headerValue) || - !headerValue.StartsWith(ApiKeyPrefix, StringComparison.OrdinalIgnoreCase)) - return AuthenticateResult.NoResult(); - - var rawKey = headerValue[ApiKeyPrefix.Length..].Trim(); - if (string.IsNullOrWhiteSpace(rawKey)) - return AuthenticateResult.Fail("API key value is empty."); - - var hashedKey = ApiKeyHasher.Hash(rawKey); - - var apiKey = await db.ApiKeys - .FirstOrDefaultAsync(k => k.Key == hashedKey); - - if (apiKey is null) - return AuthenticateResult.Fail("Invalid API key."); - - if (!apiKey.IsActive) - return AuthenticateResult.Fail("API key is inactive."); - - if (apiKey.ExpiresAt.HasValue && apiKey.ExpiresAt.Value < DateTimeOffset.UtcNow) - return AuthenticateResult.Fail("API key has expired."); - - var claims = new[] - { - new Claim("OrganizationId", apiKey.OrganizationId.ToString()), - new Claim("OrganizationRole", "Admin") - }; - - var identity = new ClaimsIdentity(claims, Scheme.Name); - var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name); - - return AuthenticateResult.Success(ticket); - } -} +using System.Security.Claims; +using System.Text.Encodings.Web; +using MicCheck.Api.Common.Security.ApiKeys; +using MicCheck.Api.Data; +using Microsoft.AspNetCore.Authentication; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace MicCheck.Api.Common.Security.Authentication; + +public class ApiKeyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, MicCheckDbContext db) + : AuthenticationHandler(options, logger, encoder) +{ + public const string SchemeName = "ApiKey"; + private const string ApiKeyPrefix = "Api-Key "; + + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.TryGetValue("Authorization", out var authHeader)) + return AuthenticateResult.NoResult(); + + var headerValue = authHeader.FirstOrDefault(); + if (string.IsNullOrWhiteSpace(headerValue) || + !headerValue.StartsWith(ApiKeyPrefix, StringComparison.OrdinalIgnoreCase)) + return AuthenticateResult.NoResult(); + + var rawKey = headerValue[ApiKeyPrefix.Length..].Trim(); + if (string.IsNullOrWhiteSpace(rawKey)) + return AuthenticateResult.Fail("API key value is empty."); + + var hashedKey = ApiKeyHasher.Hash(rawKey); + + var apiKey = await db.ApiKeys + .FirstOrDefaultAsync(k => k.Key == hashedKey); + + if (apiKey is null) + return AuthenticateResult.Fail("Invalid API key."); + + if (!apiKey.IsActive) + return AuthenticateResult.Fail("API key is inactive."); + + if (apiKey.ExpiresAt.HasValue && apiKey.ExpiresAt.Value < DateTimeOffset.UtcNow) + return AuthenticateResult.Fail("API key has expired."); + + var claims = new[] + { + new Claim("OrganizationId", apiKey.OrganizationId.ToString()), + new Claim("OrganizationRole", "Admin") + }; + + var identity = new ClaimsIdentity(claims, Scheme.Name); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name); + + return AuthenticateResult.Success(ticket); + } +} diff --git a/src/api/MicCheck.Api/Authentication/EnvironmentKeyAuthenticationHandler.cs b/src/api/MicCheck.Api/Common/Security/Authentication/EnvironmentKeyAuthenticationHandler.cs old mode 100644 new mode 100755 similarity index 83% rename from src/api/MicCheck.Api/Authentication/EnvironmentKeyAuthenticationHandler.cs rename to src/api/MicCheck.Api/Common/Security/Authentication/EnvironmentKeyAuthenticationHandler.cs index 42cfe0f..42ba736 --- a/src/api/MicCheck.Api/Authentication/EnvironmentKeyAuthenticationHandler.cs +++ b/src/api/MicCheck.Api/Common/Security/Authentication/EnvironmentKeyAuthenticationHandler.cs @@ -1,45 +1,41 @@ -using System.Security.Claims; -using System.Text.Encodings.Web; -using MicCheck.Api.Data; -using Microsoft.AspNetCore.Authentication; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; - -namespace MicCheck.Api.Authentication; - -public class EnvironmentKeyAuthenticationHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - MicCheckDbContext db) - : AuthenticationHandler(options, logger, encoder) -{ - public const string SchemeName = "EnvironmentKey"; - - protected override async Task HandleAuthenticateAsync() - { - if (!Request.Headers.TryGetValue("X-Environment-Key", out var keyValues)) - return AuthenticateResult.NoResult(); - - var key = keyValues.FirstOrDefault(); - if (string.IsNullOrWhiteSpace(key)) - return AuthenticateResult.Fail("X-Environment-Key header is empty."); - - var environment = await db.Environments - .FirstOrDefaultAsync(e => e.ApiKey == key); - - if (environment is null) - return AuthenticateResult.Fail("Invalid environment key."); - - var claims = new[] - { - new Claim("EnvironmentId", environment.Id.ToString()), - new Claim("ProjectId", environment.ProjectId.ToString()) - }; - - var identity = new ClaimsIdentity(claims, Scheme.Name); - var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name); - - return AuthenticateResult.Success(ticket); - } -} +using System.Security.Claims; +using System.Text.Encodings.Web; +using MicCheck.Api.Data; +using Microsoft.AspNetCore.Authentication; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace MicCheck.Api.Common.Security.Authentication; + +public class EnvironmentKeyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, MicCheckDbContext db) + : AuthenticationHandler(options, logger, encoder) +{ + public const string SchemeName = "EnvironmentKey"; + + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.TryGetValue("X-Environment-Key", out var keyValues)) + return AuthenticateResult.NoResult(); + + var key = keyValues.FirstOrDefault(); + if (string.IsNullOrWhiteSpace(key)) + return AuthenticateResult.Fail("X-Environment-Key header is empty."); + + var environment = await db.Environments + .FirstOrDefaultAsync(e => e.ApiKey == key); + + if (environment is null) + return AuthenticateResult.Fail("Invalid environment key."); + + var claims = new[] + { + new Claim("EnvironmentId", environment.Id.ToString()), + new Claim("ProjectId", environment.ProjectId.ToString()) + }; + + var identity = new ClaimsIdentity(claims, Scheme.Name); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name); + + return AuthenticateResult.Success(ticket); + } +} diff --git a/src/api/MicCheck.Api/Authorization/AuthEndpoints.cs b/src/api/MicCheck.Api/Common/Security/Authorization/AuthEndpoints.cs old mode 100644 new mode 100755 similarity index 72% rename from src/api/MicCheck.Api/Authorization/AuthEndpoints.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/AuthEndpoints.cs index 77b1477..c413ff9 --- a/src/api/MicCheck.Api/Authorization/AuthEndpoints.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/AuthEndpoints.cs @@ -1,66 +1,58 @@ -using Microsoft.AspNetCore.Mvc; - -namespace MicCheck.Api.Authorization; - -public static class AuthEndpoints -{ - public static void MapAuthEndpoints(this WebApplication app) - { - var group = app.MapGroup("/api/v1/auth").AllowAnonymous().WithTags("Auth"); - - group.MapPost("/login", async ( - [FromBody] LoginRequest request, - AuthService authService, - CancellationToken ct) => - { - if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) - return Results.BadRequest("Email and password are required."); - - var response = await authService.LoginAsync(request.Email, request.Password, ct); - return response is null - ? Results.Unauthorized() - : Results.Ok(response); - }).WithName("Login"); - - group.MapPost("/register", async ( - [FromBody] RegisterRequest request, - AuthService authService, - CancellationToken ct) => - { - if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) - return Results.BadRequest("Email and password are required."); - - var response = await authService.RegisterAsync( - request.Email, request.Password, - request.FirstName, request.LastName, - request.OrganizationName, ct); - - return response is null - ? Results.Conflict("An account with this email already exists.") - : Results.Ok(response); - }).WithName("Register"); - - group.MapPost("/refresh", async ( - [FromBody] RefreshRequest request, - AuthService authService, - CancellationToken ct) => - { - if (string.IsNullOrWhiteSpace(request.Token)) - return Results.BadRequest("Refresh token is required."); - - var response = await authService.RefreshAsync(request.Token, ct); - return response is null - ? Results.Unauthorized() - : Results.Ok(response); - }).WithName("RefreshToken"); - - group.MapPost("/logout", async ( - [FromBody] LogoutRequest request, - AuthService authService, - CancellationToken ct) => - { - await authService.LogoutAsync(request.Token, ct); - return Results.NoContent(); - }).WithName("Logout"); - } -} +using Microsoft.AspNetCore.Mvc; + +namespace MicCheck.Api.Common.Security.Authorization; + +public static class AuthEndpoints +{ + public static void MapAuthEndpoints(this WebApplication app) + { + var group = app.MapGroup("/api/v1/auth").AllowAnonymous().WithTags("Auth"); + + group.MapPost("/login", async ([FromBody] LoginRequest request, AuthService authService, CancellationToken ct) => + { + if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) + return Results.BadRequest("Email and password are required."); + + var response = await authService.LoginAsync(request.Email, request.Password, ct); + return response is null + ? Results.Unauthorized() + : Results.Ok(response); + + }).WithName("Login"); + + group.MapPost("/register", async ([FromBody] RegisterRequest request, AuthService authService, CancellationToken ct) => + { + if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) + return Results.BadRequest("Email and password are required."); + + var response = await authService.RegisterAsync( + request.Email, request.Password, + request.FirstName, request.LastName, + request.OrganizationName, ct); + + return response is null + ? Results.Conflict("An account with this email already exists.") + : Results.Ok(response); + + }).WithName("Register"); + + group.MapPost("/refresh", async ([FromBody] RefreshRequest request, AuthService authService, CancellationToken ct) => + { + if (string.IsNullOrWhiteSpace(request.Token)) + return Results.BadRequest("Refresh token is required."); + + var response = await authService.RefreshAsync(request.Token, ct); + return response is null + ? Results.Unauthorized() + : Results.Ok(response); + + }).WithName("RefreshToken"); + + group.MapPost("/logout", async ([FromBody] LogoutRequest request, AuthService authService, CancellationToken ct) => + { + await authService.LogoutAsync(request.Token, ct); + return Results.NoContent(); + + }).WithName("Logout"); + } +} diff --git a/src/api/MicCheck.Api/Authorization/AuthService.cs b/src/api/MicCheck.Api/Common/Security/Authorization/AuthService.cs old mode 100644 new mode 100755 similarity index 95% rename from src/api/MicCheck.Api/Authorization/AuthService.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/AuthService.cs index 714ced0..141b479 --- a/src/api/MicCheck.Api/Authorization/AuthService.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/AuthService.cs @@ -1,145 +1,145 @@ -using System.Security.Cryptography; -using MicCheck.Api.Data; -using MicCheck.Api.Organizations; -using MicCheck.Api.Users; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; - -namespace MicCheck.Api.Authorization; - -public class AuthService( - MicCheckDbContext db, - ITokenService tokenService, - IPasswordHasher passwordHasher) -{ - public async Task LoginAsync(string email, string password, CancellationToken ct = default) - { - var user = await db.Users - .Include(u => u.Organizations) - .FirstOrDefaultAsync(u => u.Email == email && u.IsActive, ct); - - if (user is null) - return null; - - var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password); - if (result == PasswordVerificationResult.Failed) - return null; - - var accessToken = tokenService.GenerateToken(user); - var refreshTokenValue = GenerateSecureToken(); - - db.RefreshTokens.Add(new RefreshToken - { - Token = refreshTokenValue, - UserId = user.Id, - ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), - CreatedAt = DateTimeOffset.UtcNow - }); - - user.LastLoginAt = DateTimeOffset.UtcNow; - await db.SaveChangesAsync(ct); - - return new LoginResponse(accessToken.Token, refreshTokenValue, accessToken.ExpiresAt); - } - - public async Task RegisterAsync( - string email, string password, - string firstName, string lastName, - string organizationName, - CancellationToken ct = default) - { - if (await db.Users.AnyAsync(u => u.Email == email, ct)) - return null; - - var user = new User - { - Email = email, - FirstName = firstName, - LastName = lastName, - IsActive = true, - CreatedAt = DateTimeOffset.UtcNow, - PasswordHash = string.Empty - }; - user.PasswordHash = passwordHasher.HashPassword(user, password); - - db.Users.Add(user); - await db.SaveChangesAsync(ct); - - var organization = new Organization - { - Name = organizationName, - CreatedAt = DateTimeOffset.UtcNow - }; - db.Organizations.Add(organization); - await db.SaveChangesAsync(ct); - - db.OrganizationUsers.Add(new OrganizationUser - { - OrganizationId = organization.Id, - UserId = user.Id, - Role = OrganizationRole.Admin - }); - await db.SaveChangesAsync(ct); - - await db.Entry(user).Collection(u => u.Organizations).LoadAsync(ct); - - var accessToken = tokenService.GenerateToken(user); - var refreshTokenValue = GenerateSecureToken(); - - db.RefreshTokens.Add(new RefreshToken - { - Token = refreshTokenValue, - UserId = user.Id, - ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), - CreatedAt = DateTimeOffset.UtcNow - }); - await db.SaveChangesAsync(ct); - - return new LoginResponse(accessToken.Token, refreshTokenValue, accessToken.ExpiresAt); - } - - public async Task RefreshAsync(string refreshToken, CancellationToken ct = default) - { - var token = await db.RefreshTokens - .Include(rt => rt.User) - .ThenInclude(u => u.Organizations) - .FirstOrDefaultAsync(rt => rt.Token == refreshToken && !rt.IsRevoked, ct); - - if (token is null || token.ExpiresAt < DateTimeOffset.UtcNow) - return null; - - token.IsRevoked = true; - - var accessToken = tokenService.GenerateToken(token.User); - var newRefreshTokenValue = GenerateSecureToken(); - - db.RefreshTokens.Add(new RefreshToken - { - Token = newRefreshTokenValue, - UserId = token.UserId, - ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), - CreatedAt = DateTimeOffset.UtcNow - }); - await db.SaveChangesAsync(ct); - - return new LoginResponse(accessToken.Token, newRefreshTokenValue, accessToken.ExpiresAt); - } - - public async Task LogoutAsync(string refreshToken, CancellationToken ct = default) - { - var token = await db.RefreshTokens - .FirstOrDefaultAsync(rt => rt.Token == refreshToken && !rt.IsRevoked, ct); - - if (token is null) - return; - - token.IsRevoked = true; - await db.SaveChangesAsync(ct); - } - - private static string GenerateSecureToken() - { - var bytes = RandomNumberGenerator.GetBytes(64); - return Convert.ToBase64String(bytes); - } -} +using System.Security.Cryptography; +using MicCheck.Api.Data; +using MicCheck.Api.Organizations; +using MicCheck.Api.Users; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Common.Security.Authorization; + +public class AuthService( + MicCheckDbContext db, + ITokenService tokenService, + IPasswordHasher passwordHasher) +{ + public async Task LoginAsync(string email, string password, CancellationToken ct = default) + { + var user = await db.Users + .Include(u => u.Organizations) + .FirstOrDefaultAsync(u => u.Email == email && u.IsActive, ct); + + if (user is null) + return null; + + var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password); + if (result == PasswordVerificationResult.Failed) + return null; + + var accessToken = tokenService.GenerateToken(user); + var refreshTokenValue = GenerateSecureToken(); + + db.RefreshTokens.Add(new RefreshToken + { + Token = refreshTokenValue, + UserId = user.Id, + ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), + CreatedAt = DateTimeOffset.UtcNow + }); + + user.LastLoginAt = DateTimeOffset.UtcNow; + await db.SaveChangesAsync(ct); + + return new LoginResponse(accessToken.Token, refreshTokenValue, accessToken.ExpiresAt); + } + + public async Task RegisterAsync( + string email, string password, + string firstName, string lastName, + string organizationName, + CancellationToken ct = default) + { + if (await db.Users.AnyAsync(u => u.Email == email, ct)) + return null; + + var user = new User + { + Email = email, + FirstName = firstName, + LastName = lastName, + IsActive = true, + CreatedAt = DateTimeOffset.UtcNow, + PasswordHash = string.Empty + }; + user.PasswordHash = passwordHasher.HashPassword(user, password); + + db.Users.Add(user); + await db.SaveChangesAsync(ct); + + var organization = new Organization + { + Name = organizationName, + CreatedAt = DateTimeOffset.UtcNow + }; + db.Organizations.Add(organization); + await db.SaveChangesAsync(ct); + + db.OrganizationUsers.Add(new OrganizationUser + { + OrganizationId = organization.Id, + UserId = user.Id, + Role = OrganizationRole.Admin + }); + await db.SaveChangesAsync(ct); + + await db.Entry(user).Collection(u => u.Organizations).LoadAsync(ct); + + var accessToken = tokenService.GenerateToken(user); + var refreshTokenValue = GenerateSecureToken(); + + db.RefreshTokens.Add(new RefreshToken + { + Token = refreshTokenValue, + UserId = user.Id, + ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), + CreatedAt = DateTimeOffset.UtcNow + }); + await db.SaveChangesAsync(ct); + + return new LoginResponse(accessToken.Token, refreshTokenValue, accessToken.ExpiresAt); + } + + public async Task RefreshAsync(string refreshToken, CancellationToken ct = default) + { + var token = await db.RefreshTokens + .Include(rt => rt.User) + .ThenInclude(u => u.Organizations) + .FirstOrDefaultAsync(rt => rt.Token == refreshToken && !rt.IsRevoked, ct); + + if (token is null || token.ExpiresAt < DateTimeOffset.UtcNow) + return null; + + token.IsRevoked = true; + + var accessToken = tokenService.GenerateToken(token.User); + var newRefreshTokenValue = GenerateSecureToken(); + + db.RefreshTokens.Add(new RefreshToken + { + Token = newRefreshTokenValue, + UserId = token.UserId, + ExpiresAt = DateTimeOffset.UtcNow.AddDays(30), + CreatedAt = DateTimeOffset.UtcNow + }); + await db.SaveChangesAsync(ct); + + return new LoginResponse(accessToken.Token, newRefreshTokenValue, accessToken.ExpiresAt); + } + + public async Task LogoutAsync(string refreshToken, CancellationToken ct = default) + { + var token = await db.RefreshTokens + .FirstOrDefaultAsync(rt => rt.Token == refreshToken && !rt.IsRevoked, ct); + + if (token is null) + return; + + token.IsRevoked = true; + await db.SaveChangesAsync(ct); + } + + private static string GenerateSecureToken() + { + var bytes = RandomNumberGenerator.GetBytes(64); + return Convert.ToBase64String(bytes); + } +} diff --git a/src/api/MicCheck.Api/Authorization/AuthorizationPolicies.cs b/src/api/MicCheck.Api/Common/Security/Authorization/AuthorizationPolicies.cs old mode 100644 new mode 100755 similarity index 78% rename from src/api/MicCheck.Api/Authorization/AuthorizationPolicies.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/AuthorizationPolicies.cs index 005befd..9d1d692 --- a/src/api/MicCheck.Api/Authorization/AuthorizationPolicies.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/AuthorizationPolicies.cs @@ -1,8 +1,8 @@ -namespace MicCheck.Api.Authorization; - -public static class AuthorizationPolicies -{ - public const string FlagsApiAccess = "FlagsApiAccess"; - public const string AdminApiAccess = "AdminApiAccess"; - public const string OrganizationAdmin = "OrganizationAdmin"; -} +namespace MicCheck.Api.Common.Security.Authorization; + +public static class AuthorizationPolicies +{ + public const string FlagsApiAccess = "FlagsApiAccess"; + public const string AdminApiAccess = "AdminApiAccess"; + public const string OrganizationAdmin = "OrganizationAdmin"; +} diff --git a/src/api/MicCheck.Api/Authorization/LoginRequest.cs b/src/api/MicCheck.Api/Common/Security/Authorization/LoginRequest.cs old mode 100644 new mode 100755 similarity index 51% rename from src/api/MicCheck.Api/Authorization/LoginRequest.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/LoginRequest.cs index f1fbd85..290e81e --- a/src/api/MicCheck.Api/Authorization/LoginRequest.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/LoginRequest.cs @@ -1,3 +1,3 @@ -namespace MicCheck.Api.Authorization; - -public record LoginRequest(string Email, string Password); +namespace MicCheck.Api.Common.Security.Authorization; + +public record LoginRequest(string Email, string Password); diff --git a/src/api/MicCheck.Api/Authorization/LoginResponse.cs b/src/api/MicCheck.Api/Common/Security/Authorization/LoginResponse.cs old mode 100644 new mode 100755 similarity index 61% rename from src/api/MicCheck.Api/Authorization/LoginResponse.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/LoginResponse.cs index e13a8d8..8e2478d --- a/src/api/MicCheck.Api/Authorization/LoginResponse.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/LoginResponse.cs @@ -1,3 +1,3 @@ -namespace MicCheck.Api.Authorization; - -public record LoginResponse(string AccessToken, string RefreshToken, DateTime ExpiresAt); +namespace MicCheck.Api.Common.Security.Authorization; + +public record LoginResponse(string AccessToken, string RefreshToken, DateTime ExpiresAt); diff --git a/src/api/MicCheck.Api/Common/Security/Authorization/LogoutRequest.cs b/src/api/MicCheck.Api/Common/Security/Authorization/LogoutRequest.cs new file mode 100755 index 0000000..bef9cb9 --- /dev/null +++ b/src/api/MicCheck.Api/Common/Security/Authorization/LogoutRequest.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Common.Security.Authorization; + +public record LogoutRequest(string Token); diff --git a/src/api/MicCheck.Api/Authorization/ProjectPermission.cs b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermission.cs old mode 100644 new mode 100755 similarity index 78% rename from src/api/MicCheck.Api/Authorization/ProjectPermission.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermission.cs index 83d795b..b5308f6 --- a/src/api/MicCheck.Api/Authorization/ProjectPermission.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermission.cs @@ -1,17 +1,17 @@ -namespace MicCheck.Api.Authorization; - -public enum ProjectPermission -{ - ViewProject, - CreateFeature, - EditFeature, - DeleteFeature, - CreateEnvironment, - EditEnvironment, - DeleteEnvironment, - CreateSegment, - EditSegment, - DeleteSegment, - ManageWebhooks, - ViewAuditLog -} +namespace MicCheck.Api.Common.Security.Authorization; + +public enum ProjectPermission +{ + ViewProject, + CreateFeature, + EditFeature, + DeleteFeature, + CreateEnvironment, + EditEnvironment, + DeleteEnvironment, + CreateSegment, + EditSegment, + DeleteSegment, + ManageWebhooks, + ViewAuditLog +} diff --git a/src/api/MicCheck.Api/Authorization/ProjectPermissionRequirement.cs b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirement.cs old mode 100644 new mode 100755 similarity index 80% rename from src/api/MicCheck.Api/Authorization/ProjectPermissionRequirement.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirement.cs index af864db..503447a --- a/src/api/MicCheck.Api/Authorization/ProjectPermissionRequirement.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirement.cs @@ -1,10 +1,10 @@ -using Microsoft.AspNetCore.Authorization; - -namespace MicCheck.Api.Authorization; - -public class ProjectPermissionRequirement : IAuthorizationRequirement -{ - public ProjectPermission Permission { get; } - - public ProjectPermissionRequirement(ProjectPermission permission) => Permission = permission; -} +using Microsoft.AspNetCore.Authorization; + +namespace MicCheck.Api.Common.Security.Authorization; + +public class ProjectPermissionRequirement : IAuthorizationRequirement +{ + public ProjectPermission Permission { get; } + + public ProjectPermissionRequirement(ProjectPermission permission) => Permission = permission; +} diff --git a/src/api/MicCheck.Api/Authorization/ProjectPermissionRequirementHandler.cs b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirementHandler.cs old mode 100644 new mode 100755 similarity index 93% rename from src/api/MicCheck.Api/Authorization/ProjectPermissionRequirementHandler.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirementHandler.cs index c550931..00a4237 --- a/src/api/MicCheck.Api/Authorization/ProjectPermissionRequirementHandler.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/ProjectPermissionRequirementHandler.cs @@ -1,54 +1,54 @@ -using System.IdentityModel.Tokens.Jwt; -using MicCheck.Api.Data; -using MicCheck.Api.Organizations; -using Microsoft.AspNetCore.Authorization; -using Microsoft.EntityFrameworkCore; - -namespace MicCheck.Api.Authorization; - -public class ProjectPermissionRequirementHandler( - MicCheckDbContext db, - IHttpContextAccessor httpContextAccessor) - : AuthorizationHandler -{ - protected override async Task HandleRequirementAsync( - AuthorizationHandlerContext context, - ProjectPermissionRequirement requirement) - { - var userIdClaim = context.User.FindFirst(JwtRegisteredClaimNames.Sub); - if (userIdClaim is null || !int.TryParse(userIdClaim.Value, out var userId)) - { - context.Fail(); - return; - } - - if (context.User.HasClaim("OrganizationRole", OrganizationRole.Admin.ToString())) - { - context.Succeed(requirement); - return; - } - - var httpContext = httpContextAccessor.HttpContext; - if (httpContext is null || - !httpContext.Request.RouteValues.TryGetValue("projectId", out var projectIdValue) || - !int.TryParse(projectIdValue?.ToString(), out var projectId)) - { - context.Fail(); - return; - } - - var permission = await db.UserProjectPermissions - .FirstOrDefaultAsync(p => p.UserId == userId && p.ProjectId == projectId); - - if (permission is null) - { - context.Fail(); - return; - } - - if (permission.IsAdmin || permission.Permissions.Contains(requirement.Permission)) - context.Succeed(requirement); - else - context.Fail(); - } -} +using System.IdentityModel.Tokens.Jwt; +using MicCheck.Api.Data; +using MicCheck.Api.Organizations; +using Microsoft.AspNetCore.Authorization; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Common.Security.Authorization; + +public class ProjectPermissionRequirementHandler( + MicCheckDbContext db, + IHttpContextAccessor httpContextAccessor) + : AuthorizationHandler +{ + protected override async Task HandleRequirementAsync( + AuthorizationHandlerContext context, + ProjectPermissionRequirement requirement) + { + var userIdClaim = context.User.FindFirst(JwtRegisteredClaimNames.Sub); + if (userIdClaim is null || !int.TryParse(userIdClaim.Value, out var userId)) + { + context.Fail(); + return; + } + + if (context.User.HasClaim("OrganizationRole", OrganizationRole.Admin.ToString())) + { + context.Succeed(requirement); + return; + } + + var httpContext = httpContextAccessor.HttpContext; + if (httpContext is null || + !httpContext.Request.RouteValues.TryGetValue("projectId", out var projectIdValue) || + !int.TryParse(projectIdValue?.ToString(), out var projectId)) + { + context.Fail(); + return; + } + + var permission = await db.UserProjectPermissions + .FirstOrDefaultAsync(p => p.UserId == userId && p.ProjectId == projectId); + + if (permission is null) + { + context.Fail(); + return; + } + + if (permission.IsAdmin || permission.Permissions.Contains(requirement.Permission)) + context.Succeed(requirement); + else + context.Fail(); + } +} diff --git a/src/api/MicCheck.Api/Common/Security/Authorization/RefreshRequest.cs b/src/api/MicCheck.Api/Common/Security/Authorization/RefreshRequest.cs new file mode 100755 index 0000000..00f4c30 --- /dev/null +++ b/src/api/MicCheck.Api/Common/Security/Authorization/RefreshRequest.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Common.Security.Authorization; + +public record RefreshRequest(string Token); diff --git a/src/api/MicCheck.Api/Authorization/RegisterRequest.cs b/src/api/MicCheck.Api/Common/Security/Authorization/RegisterRequest.cs old mode 100644 new mode 100755 similarity index 69% rename from src/api/MicCheck.Api/Authorization/RegisterRequest.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/RegisterRequest.cs index 58dcffe..7f3ce05 --- a/src/api/MicCheck.Api/Authorization/RegisterRequest.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/RegisterRequest.cs @@ -1,8 +1,8 @@ -namespace MicCheck.Api.Authorization; - -public record RegisterRequest( - string Email, - string Password, - string FirstName, - string LastName, - string OrganizationName); +namespace MicCheck.Api.Common.Security.Authorization; + +public record RegisterRequest( + string Email, + string Password, + string FirstName, + string LastName, + string OrganizationName); diff --git a/src/api/MicCheck.Api/Authorization/TokenResponse.cs b/src/api/MicCheck.Api/Common/Security/Authorization/TokenResponse.cs old mode 100644 new mode 100755 similarity index 52% rename from src/api/MicCheck.Api/Authorization/TokenResponse.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/TokenResponse.cs index 0439497..1d26f82 --- a/src/api/MicCheck.Api/Authorization/TokenResponse.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/TokenResponse.cs @@ -1,3 +1,3 @@ -namespace MicCheck.Api.Authorization; - -public record TokenResponse(string Token, DateTime ExpiresAt); +namespace MicCheck.Api.Common.Security.Authorization; + +public record TokenResponse(string Token, DateTime ExpiresAt); diff --git a/src/api/MicCheck.Api/Authorization/TokenService.cs b/src/api/MicCheck.Api/Common/Security/Authorization/TokenService.cs old mode 100644 new mode 100755 similarity index 86% rename from src/api/MicCheck.Api/Authorization/TokenService.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/TokenService.cs index 089fb53..0c57d2c --- a/src/api/MicCheck.Api/Authorization/TokenService.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/TokenService.cs @@ -1,52 +1,55 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Text; -using MicCheck.Api.Users; -using Microsoft.IdentityModel.Tokens; - -namespace MicCheck.Api.Authorization; - -public class TokenService(IConfiguration configuration) : ITokenService -{ - public TokenResponse GenerateToken(User user) - { - var secretKey = configuration["Jwt:SecretKey"] - ?? throw new InvalidOperationException("Jwt:SecretKey is not configured."); - var issuer = configuration["Jwt:Issuer"] - ?? throw new InvalidOperationException("Jwt:Issuer is not configured."); - var audience = configuration["Jwt:Audience"] - ?? throw new InvalidOperationException("Jwt:Audience is not configured."); - var expiryMinutes = int.Parse(configuration["Jwt:ExpiryMinutes"] ?? "60"); - - var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)); - var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); - var expiresAt = DateTime.UtcNow.AddMinutes(expiryMinutes); - - var claims = new List - { - new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), - new(JwtRegisteredClaimNames.Email, user.Email), - new(JwtRegisteredClaimNames.GivenName, user.FirstName), - new(JwtRegisteredClaimNames.FamilyName, user.LastName), - new(JwtRegisteredClaimNames.Iat, - DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), - ClaimValueTypes.Integer64), - new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - }; - - foreach (var org in user.Organizations) - { - claims.Add(new Claim("OrganizationId", org.OrganizationId.ToString())); - claims.Add(new Claim("OrganizationRole", org.Role.ToString())); - } - - var token = new JwtSecurityToken( - issuer: issuer, - audience: audience, - claims: claims, - expires: expiresAt, - signingCredentials: credentials); - - return new TokenResponse(new JwtSecurityTokenHandler().WriteToken(token), expiresAt); - } -} +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using MicCheck.Api.Users; +using Microsoft.IdentityModel.Tokens; + +namespace MicCheck.Api.Common.Security.Authorization; + +public class TokenService(IConfiguration configuration) : ITokenService +{ + public TokenResponse GenerateToken(User user) + { + var secretKey = configuration["Jwt:SecretKey"] + ?? throw new InvalidOperationException("Jwt:SecretKey is not configured."); + var issuer = configuration["Jwt:Issuer"] + ?? throw new InvalidOperationException("Jwt:Issuer is not configured."); + var audience = configuration["Jwt:Audience"] + ?? throw new InvalidOperationException("Jwt:Audience is not configured."); + var expiryMinutes = int.Parse(configuration["Jwt:ExpiryMinutes"] ?? "60"); + + var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)); + var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + var expiresAt = DateTime.UtcNow.AddMinutes(expiryMinutes); + + var claims = new List + { + new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), + new(JwtRegisteredClaimNames.Email, user.Email), + new(JwtRegisteredClaimNames.GivenName, user.FirstName), + new(JwtRegisteredClaimNames.FamilyName, user.LastName), + new(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64), + new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + }; + + foreach (var org in user.Organizations) + { + claims.Add(new Claim("OrganizationId", org.OrganizationId.ToString())); + claims.Add(new Claim("OrganizationRole", org.Role.ToString())); + } + + var token = new JwtSecurityToken( + issuer: issuer, + audience: audience, + claims: claims, + expires: expiresAt, + signingCredentials: credentials); + + return new TokenResponse(new JwtSecurityTokenHandler().WriteToken(token), expiresAt); + } +} + +public interface ITokenService +{ + TokenResponse GenerateToken(User user); +} diff --git a/src/api/MicCheck.Api/Authorization/UserProjectPermission.cs b/src/api/MicCheck.Api/Common/Security/Authorization/UserProjectPermission.cs old mode 100644 new mode 100755 similarity index 77% rename from src/api/MicCheck.Api/Authorization/UserProjectPermission.cs rename to src/api/MicCheck.Api/Common/Security/Authorization/UserProjectPermission.cs index 34001bd..b265845 --- a/src/api/MicCheck.Api/Authorization/UserProjectPermission.cs +++ b/src/api/MicCheck.Api/Common/Security/Authorization/UserProjectPermission.cs @@ -1,9 +1,9 @@ -namespace MicCheck.Api.Authorization; - -public class UserProjectPermission -{ - public int UserId { get; init; } - public int ProjectId { get; init; } - public List Permissions { get; set; } = []; - public bool IsAdmin { get; set; } -} +namespace MicCheck.Api.Common.Security.Authorization; + +public class UserProjectPermission +{ + public int UserId { get; init; } + public int ProjectId { get; init; } + public List Permissions { get; set; } = []; + public bool IsAdmin { get; set; } +} diff --git a/src/api/MicCheck.Api/Data/Configurations/ApiKeyConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/ApiKeyConfiguration.cs old mode 100644 new mode 100755 index c674ed8..82bfbda --- a/src/api/MicCheck.Api/Data/Configurations/ApiKeyConfiguration.cs +++ b/src/api/MicCheck.Api/Data/Configurations/ApiKeyConfiguration.cs @@ -1,19 +1,19 @@ -using MicCheck.Api.ApiKeys; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace MicCheck.Api.Data.Configurations; - -public class ApiKeyConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(k => k.Id); - builder.Property(k => k.Key).HasMaxLength(512).IsRequired(); - builder.Property(k => k.Prefix).HasMaxLength(8).IsRequired(); - builder.Property(k => k.Name).HasMaxLength(200).IsRequired(); - builder.Property(k => k.CreatedAt).IsRequired(); - - builder.HasIndex(k => k.Key).IsUnique(); - } -} +using MicCheck.Api.Common.Security.ApiKeys; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace MicCheck.Api.Data.Configurations; + +public class ApiKeyConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(k => k.Id); + builder.Property(k => k.Key).HasMaxLength(512).IsRequired(); + builder.Property(k => k.Prefix).HasMaxLength(8).IsRequired(); + builder.Property(k => k.Name).HasMaxLength(200).IsRequired(); + builder.Property(k => k.CreatedAt).IsRequired(); + + builder.HasIndex(k => k.Key).IsUnique(); + } +} diff --git a/src/api/MicCheck.Api/Data/Configurations/AuditLogConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/AuditLogConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/EnvironmentConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/EnvironmentConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/FeatureConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/FeatureConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/FeatureSegmentConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/FeatureSegmentConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/FeatureStateConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/FeatureStateConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs new file mode 100644 index 0000000..087ca85 --- /dev/null +++ b/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs @@ -0,0 +1,19 @@ +using MicCheck.Api.Features; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace MicCheck.Api.Data.Configurations; + +public class FeatureUsageDailyConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(u => u.Id); + builder.Property(u => u.FeatureName).HasMaxLength(150).IsRequired(); + builder.Property(u => u.UpdatedAt).IsRequired(); + builder.Property(u => u.Count).IsRequired(); + + builder.HasIndex(u => new { u.EnvironmentId, u.FeatureId, u.UsageDate }).IsUnique(); + builder.HasIndex(u => new { u.EnvironmentId, u.UsageDate }); + } +} diff --git a/src/api/MicCheck.Api/Data/Configurations/IdentityConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/IdentityConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/IdentityTraitConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/IdentityTraitConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/OrganizationConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/OrganizationConfiguration.cs old mode 100644 new mode 100755 index 0348cdb..b7fb821 --- a/src/api/MicCheck.Api/Data/Configurations/OrganizationConfiguration.cs +++ b/src/api/MicCheck.Api/Data/Configurations/OrganizationConfiguration.cs @@ -11,6 +11,8 @@ public class OrganizationConfiguration : IEntityTypeConfiguration builder.HasKey(o => o.Id); builder.Property(o => o.Name).HasMaxLength(200).IsRequired(); builder.Property(o => o.CreatedAt).IsRequired(); + builder.Property(o => o.InviteToken).HasMaxLength(64); + builder.HasIndex(o => o.InviteToken).IsUnique().HasFilter("\"InviteToken\" IS NOT NULL"); builder.HasMany(o => o.Members) .WithOne() diff --git a/src/api/MicCheck.Api/Data/Configurations/OrganizationUserConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/OrganizationUserConfiguration.cs old mode 100644 new mode 100755 index 139525a..3b3bdfa --- a/src/api/MicCheck.Api/Data/Configurations/OrganizationUserConfiguration.cs +++ b/src/api/MicCheck.Api/Data/Configurations/OrganizationUserConfiguration.cs @@ -10,5 +10,6 @@ public class OrganizationUserConfiguration : IEntityTypeConfiguration new { ou.OrganizationId, ou.UserId }); builder.Property(ou => ou.Role).IsRequired(); + builder.Property(ou => ou.IsPrimary).IsRequired().HasDefaultValue(false); } } diff --git a/src/api/MicCheck.Api/Data/Configurations/ProjectConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/ProjectConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/RefreshTokenConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/RefreshTokenConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/SegmentConditionConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/SegmentConditionConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/SegmentConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/SegmentConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/SegmentRuleConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/SegmentRuleConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/TagConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/TagConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/UserConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/UserConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/UserProjectPermissionConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/UserProjectPermissionConfiguration.cs old mode 100644 new mode 100755 index 4722390..7035bd6 --- a/src/api/MicCheck.Api/Data/Configurations/UserProjectPermissionConfiguration.cs +++ b/src/api/MicCheck.Api/Data/Configurations/UserProjectPermissionConfiguration.cs @@ -1,22 +1,22 @@ -using MicCheck.Api.Authorization; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace MicCheck.Api.Data.Configurations; - -public class UserProjectPermissionConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(p => new { p.UserId, p.ProjectId }); - - builder.Property(p => p.Permissions) - .HasConversion( - v => string.Join(',', v.Select(p => p.ToString())), - v => string.IsNullOrEmpty(v) - ? new List() - : v.Split(',', StringSplitOptions.RemoveEmptyEntries) - .Select(Enum.Parse) - .ToList()); - } -} +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace MicCheck.Api.Data.Configurations; + +public class UserProjectPermissionConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(p => new { p.UserId, p.ProjectId }); + + builder.Property(p => p.Permissions) + .HasConversion( + v => string.Join(',', v.Select(p => p.ToString())), + v => string.IsNullOrEmpty(v) + ? new List() + : v.Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(Enum.Parse) + .ToList()); + } +} diff --git a/src/api/MicCheck.Api/Data/Configurations/WebhookConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/WebhookConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/Configurations/WebhookDeliveryLogConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/WebhookDeliveryLogConfiguration.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/DatabaseSeeder.cs b/src/api/MicCheck.Api/Data/DatabaseSeeder.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/DatabaseStartupExtensions.cs b/src/api/MicCheck.Api/Data/DatabaseStartupExtensions.cs new file mode 100755 index 0000000..49e47e2 --- /dev/null +++ b/src/api/MicCheck.Api/Data/DatabaseStartupExtensions.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Data; + +public static class DatabaseStartupExtensions +{ + public static async Task ApplyMigrationsAsync(this WebApplication app, CancellationToken ct = default) + { + using var scope = app.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + if (db.Database.ProviderName is null or "Microsoft.EntityFrameworkCore.InMemory") + return; + + await db.Database.MigrateAsync(ct); + } + + public static async Task SeedDevelopmentDataAsync(this WebApplication app, CancellationToken ct = default) + { + using var scope = app.Services.CreateScope(); + var seeder = scope.ServiceProvider.GetRequiredService(); + await seeder.SeedAsync(ct); + } +} diff --git a/src/api/MicCheck.Api/Data/DatabaseUrlParser.cs b/src/api/MicCheck.Api/Data/DatabaseUrlParser.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Data/MicCheckDbContext.cs b/src/api/MicCheck.Api/Data/MicCheckDbContext.cs old mode 100644 new mode 100755 index 13f4291..fac0cc6 --- a/src/api/MicCheck.Api/Data/MicCheckDbContext.cs +++ b/src/api/MicCheck.Api/Data/MicCheckDbContext.cs @@ -1,43 +1,44 @@ -using MicCheck.Api.ApiKeys; -using MicCheck.Api.Audit; -using MicCheck.Api.Authorization; -using MicCheck.Api.Features; -using MicCheck.Api.Identities; -using MicCheck.Api.Organizations; -using MicCheck.Api.Projects; -using MicCheck.Api.Segments; -using MicCheck.Api.Users; -using MicCheck.Api.Webhooks; -using Microsoft.EntityFrameworkCore; -using AppEnvironment = MicCheck.Api.Environments.Environment; - -namespace MicCheck.Api.Data; - -public class MicCheckDbContext : DbContext -{ - public MicCheckDbContext(DbContextOptions options) : base(options) { } - - public DbSet Organizations => Set(); - public DbSet OrganizationUsers => Set(); - public DbSet Projects => Set(); - public DbSet Environments => Set(); - public DbSet Features => Set(); - public DbSet FeatureStates => Set(); - public DbSet FeatureSegments => Set(); - public DbSet Tags => Set(); - public DbSet Segments => Set(); - public DbSet SegmentRules => Set(); - public DbSet SegmentConditions => Set(); - public DbSet Identities => Set(); - public DbSet IdentityTraits => Set(); - public DbSet AuditLogs => Set(); - public DbSet Webhooks => Set(); - public DbSet WebhookDeliveryLogs => Set(); - public DbSet ApiKeys => Set(); - public DbSet Users => Set(); - public DbSet RefreshTokens => Set(); - public DbSet UserProjectPermissions => Set(); - - protected override void OnModelCreating(ModelBuilder modelBuilder) - => modelBuilder.ApplyConfigurationsFromAssembly(typeof(MicCheckDbContext).Assembly); -} +using MicCheck.Api.Common.Security.ApiKeys; +using MicCheck.Api.Audit; +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Features; +using MicCheck.Api.Identities; +using MicCheck.Api.Organizations; +using MicCheck.Api.Projects; +using MicCheck.Api.Segments; +using MicCheck.Api.Users; +using MicCheck.Api.Webhooks; +using Microsoft.EntityFrameworkCore; +using AppEnvironment = MicCheck.Api.Environments.Environment; + +namespace MicCheck.Api.Data; + +public class MicCheckDbContext : DbContext +{ + public MicCheckDbContext(DbContextOptions options) : base(options) { } + + public DbSet Organizations => Set(); + public DbSet OrganizationUsers => Set(); + public DbSet Projects => Set(); + public DbSet Environments => Set(); + public DbSet Features => Set(); + public DbSet FeatureStates => Set(); + public DbSet FeatureSegments => Set(); + public DbSet Tags => Set(); + public DbSet Segments => Set(); + public DbSet SegmentRules => Set(); + public DbSet SegmentConditions => Set(); + public DbSet Identities => Set(); + public DbSet IdentityTraits => Set(); + public DbSet AuditLogs => Set(); + public DbSet Webhooks => Set(); + public DbSet WebhookDeliveryLogs => Set(); + public DbSet ApiKeys => Set(); + public DbSet Users => Set(); + public DbSet RefreshTokens => Set(); + public DbSet UserProjectPermissions => Set(); + public DbSet FeatureUsageDaily => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + => modelBuilder.ApplyConfigurationsFromAssembly(typeof(MicCheckDbContext).Assembly); +} diff --git a/src/api/MicCheck.Api/Dockerfile b/src/api/MicCheck.Api/Dockerfile old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/CloneEnvironmentRequest.cs b/src/api/MicCheck.Api/Environments/CloneEnvironmentRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/CreateEnvironmentRequest.cs b/src/api/MicCheck.Api/Environments/CreateEnvironmentRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/Environment.cs b/src/api/MicCheck.Api/Environments/Environment.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/EnvironmentDocumentController.cs b/src/api/MicCheck.Api/Environments/EnvironmentDocumentController.cs old mode 100644 new mode 100755 index 2522935..5185973 --- a/src/api/MicCheck.Api/Environments/EnvironmentDocumentController.cs +++ b/src/api/MicCheck.Api/Environments/EnvironmentDocumentController.cs @@ -1,20 +1,20 @@ -using MicCheck.Api.Authorization; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace MicCheck.Api.Environments; - -[ApiController] -[Route("api/v1/environment-document")] -[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] -public class EnvironmentDocumentController(EnvironmentDocumentService environmentDocumentService) : ControllerBase -{ - [HttpGet] - public async Task> Get(CancellationToken ct) - { - var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value); - var document = await environmentDocumentService.GetAsync(environmentId, ct); - - return document is null ? NotFound() : Ok(document); - } -} +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace MicCheck.Api.Environments; + +[ApiController] +[Route("api/v1/environment-document")] +[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] +public class EnvironmentDocumentController(EnvironmentDocumentService environmentDocumentService) : ControllerBase +{ + [HttpGet] + public async Task> Get(CancellationToken ct) + { + var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value); + var document = await environmentDocumentService.GetAsync(environmentId, ct); + + return document is null ? NotFound() : Ok(document); + } +} diff --git a/src/api/MicCheck.Api/Environments/EnvironmentDocumentResponse.cs b/src/api/MicCheck.Api/Environments/EnvironmentDocumentResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/EnvironmentDocumentService.cs b/src/api/MicCheck.Api/Environments/EnvironmentDocumentService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/EnvironmentResponse.cs b/src/api/MicCheck.Api/Environments/EnvironmentResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Environments/EnvironmentService.cs b/src/api/MicCheck.Api/Environments/EnvironmentService.cs old mode 100644 new mode 100755 index 6afa325..5fe015d --- a/src/api/MicCheck.Api/Environments/EnvironmentService.cs +++ b/src/api/MicCheck.Api/Environments/EnvironmentService.cs @@ -1,135 +1,135 @@ -using MicCheck.Api.ApiKeys; -using MicCheck.Api.Audit; -using MicCheck.Api.Data; -using MicCheck.Api.Features; -using Microsoft.EntityFrameworkCore; -using AppEnvironment = MicCheck.Api.Environments.Environment; - -namespace MicCheck.Api.Environments; - -public class EnvironmentService(MicCheckDbContext db, AuditService auditService) -{ - public async Task> ListByProjectAsync(int projectId, CancellationToken ct = default) - { - return await db.Environments - .Where(e => e.ProjectId == projectId) - .ToListAsync(ct); - } - - public async Task FindByApiKeyAsync(string apiKey, CancellationToken ct = default) - { - return await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct); - } - - public async Task CreateAsync(int projectId, string name, CancellationToken ct = default) - { - var apiKey = ApiKeyHasher.GenerateKey(); - - var environment = new AppEnvironment - { - Name = name, - ApiKey = apiKey, - ProjectId = projectId, - CreatedAt = DateTimeOffset.UtcNow - }; - db.Environments.Add(environment); - await db.SaveChangesAsync(ct); - - var features = await db.Features - .Where(f => f.ProjectId == projectId) - .ToListAsync(ct); - - foreach (var feature in features) - { - db.FeatureStates.Add(new FeatureState - { - FeatureId = feature.Id, - EnvironmentId = environment.Id, - Enabled = feature.DefaultEnabled, - Value = feature.InitialValue, - CreatedAt = DateTimeOffset.UtcNow, - UpdatedAt = DateTimeOffset.UtcNow - }); - } - - if (features.Count > 0) - await db.SaveChangesAsync(ct); - - var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == projectId, ct); - if (project is not null) - await auditService.LogAsync("Environment", environment.Id.ToString(), "created", - project.OrganizationId, projectId, environment.Id, ct: ct); - - return environment; - } - - public async Task UpdateAsync(string apiKey, string name, CancellationToken ct = default) - { - var environment = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct) - ?? throw new KeyNotFoundException($"Environment with key '{apiKey}' not found."); - - environment.Name = name; - await db.SaveChangesAsync(ct); - - var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == environment.ProjectId, ct); - if (project is not null) - await auditService.LogAsync("Environment", environment.Id.ToString(), "updated", - project.OrganizationId, environment.ProjectId, environment.Id, ct: ct); - - return environment; - } - - public async Task DeleteAsync(string apiKey, CancellationToken ct = default) - { - var environment = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct); - if (environment is null) return; - - db.Environments.Remove(environment); - await db.SaveChangesAsync(ct); - } - - public async Task CloneAsync(string sourceApiKey, string newName, CancellationToken ct = default) - { - var source = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == sourceApiKey, ct) - ?? throw new KeyNotFoundException($"Source environment with key '{sourceApiKey}' not found."); - - var newApiKey = ApiKeyHasher.GenerateKey(); - - var cloned = new AppEnvironment - { - Name = newName, - ApiKey = newApiKey, - ProjectId = source.ProjectId, - CreatedAt = DateTimeOffset.UtcNow - }; - db.Environments.Add(cloned); - await db.SaveChangesAsync(ct); - - var sourceStates = await db.FeatureStates - .Where(fs => fs.EnvironmentId == source.Id && fs.IdentityId == null && fs.FeatureSegmentId == null) - .ToListAsync(ct); - - foreach (var state in sourceStates) - { - db.FeatureStates.Add(new FeatureState - { - FeatureId = state.FeatureId, - EnvironmentId = cloned.Id, - Enabled = state.Enabled, - Value = state.Value, - CreatedAt = DateTimeOffset.UtcNow, - UpdatedAt = DateTimeOffset.UtcNow - }); - } - - if (sourceStates.Count > 0) - await db.SaveChangesAsync(ct); - - var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == source.ProjectId, ct); - if (project is not null) - await auditService.LogAsync("Environment", cloned.Id.ToString(), "cloned", - project.OrganizationId, source.ProjectId, cloned.Id, ct: ct); - - return cloned; - } -} +using MicCheck.Api.Common.Security.ApiKeys; +using MicCheck.Api.Audit; +using MicCheck.Api.Data; +using MicCheck.Api.Features; +using Microsoft.EntityFrameworkCore; +using AppEnvironment = MicCheck.Api.Environments.Environment; + +namespace MicCheck.Api.Environments; + +public class EnvironmentService(MicCheckDbContext db, AuditService auditService) +{ + public async Task> ListByProjectAsync(int projectId, CancellationToken ct = default) + { + return await db.Environments + .Where(e => e.ProjectId == projectId) + .ToListAsync(ct); + } + + public async Task FindByApiKeyAsync(string apiKey, CancellationToken ct = default) + { + return await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct); + } + + public async Task CreateAsync(int projectId, string name, CancellationToken ct = default) + { + var apiKey = ApiKeyHasher.GenerateKey(); + + var environment = new AppEnvironment + { + Name = name, + ApiKey = apiKey, + ProjectId = projectId, + CreatedAt = DateTimeOffset.UtcNow + }; + db.Environments.Add(environment); + await db.SaveChangesAsync(ct); + + var features = await db.Features + .Where(f => f.ProjectId == projectId) + .ToListAsync(ct); + + foreach (var feature in features) + { + db.FeatureStates.Add(new FeatureState + { + FeatureId = feature.Id, + EnvironmentId = environment.Id, + Enabled = feature.DefaultEnabled, + Value = feature.InitialValue, + CreatedAt = DateTimeOffset.UtcNow, + UpdatedAt = DateTimeOffset.UtcNow + }); + } + + if (features.Count > 0) + await db.SaveChangesAsync(ct); + + var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == projectId, ct); + if (project is not null) + await auditService.LogAsync("Environment", environment.Id.ToString(), "created", + project.OrganizationId, projectId, environment.Id, ct: ct); + + return environment; + } + + public async Task UpdateAsync(string apiKey, string name, CancellationToken ct = default) + { + var environment = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct) + ?? throw new KeyNotFoundException($"Environment with key '{apiKey}' not found."); + + environment.Name = name; + await db.SaveChangesAsync(ct); + + var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == environment.ProjectId, ct); + if (project is not null) + await auditService.LogAsync("Environment", environment.Id.ToString(), "updated", + project.OrganizationId, environment.ProjectId, environment.Id, ct: ct); + + return environment; + } + + public async Task DeleteAsync(string apiKey, CancellationToken ct = default) + { + var environment = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == apiKey, ct); + if (environment is null) return; + + db.Environments.Remove(environment); + await db.SaveChangesAsync(ct); + } + + public async Task CloneAsync(string sourceApiKey, string newName, CancellationToken ct = default) + { + var source = await db.Environments.FirstOrDefaultAsync(e => e.ApiKey == sourceApiKey, ct) + ?? throw new KeyNotFoundException($"Source environment with key '{sourceApiKey}' not found."); + + var newApiKey = ApiKeyHasher.GenerateKey(); + + var cloned = new AppEnvironment + { + Name = newName, + ApiKey = newApiKey, + ProjectId = source.ProjectId, + CreatedAt = DateTimeOffset.UtcNow + }; + db.Environments.Add(cloned); + await db.SaveChangesAsync(ct); + + var sourceStates = await db.FeatureStates + .Where(fs => fs.EnvironmentId == source.Id && fs.IdentityId == null && fs.FeatureSegmentId == null) + .ToListAsync(ct); + + foreach (var state in sourceStates) + { + db.FeatureStates.Add(new FeatureState + { + FeatureId = state.FeatureId, + EnvironmentId = cloned.Id, + Enabled = state.Enabled, + Value = state.Value, + CreatedAt = DateTimeOffset.UtcNow, + UpdatedAt = DateTimeOffset.UtcNow + }); + } + + if (sourceStates.Count > 0) + await db.SaveChangesAsync(ct); + + var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == source.ProjectId, ct); + if (project is not null) + await auditService.LogAsync("Environment", cloned.Id.ToString(), "cloned", + project.OrganizationId, source.ProjectId, cloned.Id, ct: ct); + + return cloned; + } +} diff --git a/src/api/MicCheck.Api/Environments/EnvironmentsController.cs b/src/api/MicCheck.Api/Environments/EnvironmentsController.cs old mode 100644 new mode 100755 index 30228a5..6508f2d --- a/src/api/MicCheck.Api/Environments/EnvironmentsController.cs +++ b/src/api/MicCheck.Api/Environments/EnvironmentsController.cs @@ -1,443 +1,442 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using MicCheck.Api.Webhooks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Environments; - -[ApiController] -[Route("api/v1/environments")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class EnvironmentsController(EnvironmentService environmentService, WebhookService webhookService) : ControllerBase -{ - [HttpGet] - public async Task>> List( - [FromQuery] int projectId, - [FromQuery] int page = 1, - [FromQuery] int pageSize = 20, - CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var all = await environmentService.ListByProjectAsync(projectId, ct); - var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(EnvironmentResponse.From).ToList(); - return Ok(new PaginatedResponse(all.Count, null, null, paged)); - } - - [HttpPost] - public async Task> Create(CreateEnvironmentRequest request, CancellationToken ct) - { - var environment = await environmentService.CreateAsync(request.ProjectId, request.Name, ct); - return CreatedAtAction(nameof(GetByApiKey), new { apiKey = environment.ApiKey }, EnvironmentResponse.From(environment)); - } - - [HttpGet("{apiKey}")] - public async Task> GetByApiKey(string apiKey, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - return Ok(EnvironmentResponse.From(environment)); - } - - [HttpPut("{apiKey}")] - public async Task> Update(string apiKey, UpdateEnvironmentRequest request, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var updated = await environmentService.UpdateAsync(apiKey, request.Name, ct); - return Ok(EnvironmentResponse.From(updated)); - } - - [HttpDelete("{apiKey}")] - public async Task Delete(string apiKey, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - await environmentService.DeleteAsync(apiKey, ct); - return NoContent(); - } - - [HttpPost("{apiKey}/clone")] - public async Task> Clone(string apiKey, CloneEnvironmentRequest request, CancellationToken ct) - { - var source = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (source is null) return NotFound(); - - var cloned = await environmentService.CloneAsync(apiKey, request.Name, ct); - return CreatedAtAction(nameof(GetByApiKey), new { apiKey = cloned.ApiKey }, EnvironmentResponse.From(cloned)); - } - - [HttpGet("{apiKey}/webhooks")] - public async Task>> ListWebhooks(string apiKey, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var webhooks = await webhookService.ListByEnvironmentAsync(environment.Id, ct); - return Ok(webhooks.Select(WebhookResponse.From).ToList()); - } - - [HttpPost("{apiKey}/webhooks")] - public async Task> CreateWebhook( - string apiKey, CreateWebhookRequest request, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var webhook = await webhookService.CreateAsync(environment.Id, request.Url, request.Secret, request.Enabled, ct); - return CreatedAtAction(nameof(GetByApiKey), new { apiKey }, WebhookResponse.From(webhook)); - } - - [HttpPut("{apiKey}/webhooks/{id}")] - public async Task> UpdateWebhook( - string apiKey, int id, CreateWebhookRequest request, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var webhook = await webhookService.FindByIdAsync(id, ct); - if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); - - var updated = await webhookService.UpdateAsync(id, request.Url, request.Secret, request.Enabled, ct); - return Ok(WebhookResponse.From(updated)); - } - - [HttpGet("{apiKey}/webhooks/{id}/deliveries")] - public async Task>> ListWebhookDeliveries( - string apiKey, int id, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var webhook = await webhookService.FindByIdAsync(id, ct); - if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); - - var logs = await webhookService.ListDeliveriesAsync(id, ct); - return Ok(logs.Select(WebhookDeliveryLogResponse.From).ToList()); - } - - [HttpDelete("{apiKey}/webhooks/{id}")] - public async Task DeleteWebhook(string apiKey, int id, CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var webhook = await webhookService.FindByIdAsync(id, ct); - if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); - - await webhookService.DeleteAsync(id, ct); - return NoContent(); - } - - [HttpGet("{apiKey}/audit-logs")] - public async Task>> ListAuditLogs( - string apiKey, - [FromServices] Audit.AuditLogQueryService auditLogQueryService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var (_, logs) = await auditLogQueryService.ListByEnvironmentAsync(environment.Id, new Audit.AuditLogFilter(), ct); - return Ok(logs.Select(Audit.AuditLogResponse.From).ToList()); - } - - [HttpGet("{apiKey}/identities")] - public async Task>> ListIdentities( - string apiKey, - [FromServices] Identities.AdminIdentityService adminIdentityService, - [FromQuery] int page = 1, - [FromQuery] int pageSize = 20, - CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var (total, items) = await adminIdentityService.ListAsync(environment.Id, page, pageSize, ct); - var results = items.Select(Identities.AdminIdentityResponse.From).ToList(); - return Ok(new PaginatedResponse(total, null, null, results)); - } - - [HttpPost("{apiKey}/identities")] - public async Task> CreateIdentity( - string apiKey, - [FromBody] Identities.CreateIdentityRequest request, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.CreateAsync(environment.Id, request.Identifier, ct); - if (identity is null) - return Conflict(new { error = "An identity with this identifier already exists in the environment." }); - - return CreatedAtAction(nameof(GetIdentity), new { apiKey, id = identity.Id }, - Identities.AdminIdentityResponse.From(identity)); - } - - [HttpGet("{apiKey}/identities/{id}")] - public async Task> GetIdentity( - string apiKey, int id, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - return Ok(Identities.AdminIdentityResponse.From(identity)); - } - - [HttpDelete("{apiKey}/identities/{id}")] - public async Task DeleteIdentity( - string apiKey, int id, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - - await adminIdentityService.DeleteAsync(id, ct); - return NoContent(); - } - - [HttpPut("{apiKey}/identities/{id}/traits/{key}")] - public async Task> UpsertIdentityTrait( - string apiKey, int id, string key, - [FromBody] Identities.UpsertTraitRequest request, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var result = await adminIdentityService.UpsertTraitAsync(id, environment.Id, key, request.Value, ct); - if (result is null) return NotFound(); - return Ok(result); - } - - [HttpDelete("{apiKey}/identities/{id}/traits/{key}")] - public async Task DeleteIdentityTrait( - string apiKey, int id, string key, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var deleted = await adminIdentityService.DeleteTraitAsync(id, environment.Id, key, ct); - if (!deleted) return NotFound(); - return NoContent(); - } - - [HttpGet("{apiKey}/identities/{id}/featurestates")] - public async Task>> GetIdentityFeatureStates( - string apiKey, int id, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - - var states = await adminIdentityService.GetFeatureStatesAsync(id, environment.Id, ct); - return Ok(states.Select(Features.FeatureStateResponse.From).ToList()); - } - - [HttpPut("{apiKey}/identities/{id}/featurestates/{featureId}")] - public async Task> SetIdentityFeatureState( - string apiKey, int id, int featureId, - Features.UpdateFeatureStateRequest request, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - - var state = await adminIdentityService.SetFeatureStateAsync(id, environment.Id, featureId, request.Enabled, request.Value, ct); - return Ok(Features.FeatureStateResponse.From(state)); - } - - [HttpDelete("{apiKey}/identities/{id}/featurestates/{featureId}")] - public async Task DeleteIdentityFeatureState( - string apiKey, int id, int featureId, - [FromServices] Identities.AdminIdentityService adminIdentityService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - - await adminIdentityService.DeleteFeatureStateAsync(id, environment.Id, featureId, ct); - return NoContent(); - } - - [HttpGet("{apiKey}/featurestates")] - public async Task>> ListFeatureStates( - string apiKey, - [FromServices] Features.FeatureStateService featureStateService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var states = await featureStateService.ListByEnvironmentAsync(environment.Id, ct); - return Ok(states.Select(Features.FeatureStateResponse.From).ToList()); - } - - [HttpGet("{apiKey}/featurestates/{id}")] - public async Task> GetFeatureState( - string apiKey, int id, - [FromServices] Features.FeatureStateService featureStateService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); - if (state is null) return NotFound(); - return Ok(Features.FeatureStateResponse.From(state)); - } - - [HttpPut("{apiKey}/featurestates/{id}")] - public async Task> UpdateFeatureState( - string apiKey, int id, - Features.UpdateFeatureStateRequest request, - [FromServices] Features.FeatureStateService featureStateService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); - if (state is null) return NotFound(); - - var updated = await featureStateService.UpdateAsync(id, request.Enabled, request.Value, ct); - return Ok(Features.FeatureStateResponse.From(updated)); - } - - [HttpPatch("{apiKey}/featurestates/{id}")] - public async Task> PatchFeatureState( - string apiKey, int id, - Features.PatchFeatureStateRequest request, - [FromServices] Features.FeatureStateService featureStateService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); - if (state is null) return NotFound(); - - var updated = await featureStateService.PatchAsync(id, request.Enabled, request.Value, ct); - return Ok(Features.FeatureStateResponse.From(updated)); - } - - // ─── Feature Segments ──────────────────────────────────────────────────── - - [HttpGet("{apiKey}/features/{featureId}/segments")] - public async Task>> ListFeatureSegments( - string apiKey, int featureId, - [FromServices] Features.FeatureSegmentService featureSegmentService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var results = await featureSegmentService.ListByFeatureAsync(featureId, environment.Id, ct); - return Ok(results); - } - - [HttpPost("{apiKey}/features/{featureId}/segments")] - public async Task> CreateFeatureSegment( - string apiKey, int featureId, - Features.CreateFeatureSegmentRequest request, - [FromServices] Features.FeatureSegmentService featureSegmentService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - try - { - var result = await featureSegmentService.CreateAsync( - featureId, environment.Id, request.SegmentId, request.Priority, - request.Enabled, request.Value, ct); - return Ok(result); - } - catch (KeyNotFoundException ex) - { - return NotFound(new { error = ex.Message }); - } - } - - [HttpPut("{apiKey}/features/{featureId}/segments/{id}")] - public async Task> UpdateFeatureSegment( - string apiKey, int featureId, int id, - Features.UpdateFeatureSegmentRequest request, - [FromServices] Features.FeatureSegmentService featureSegmentService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var result = await featureSegmentService.UpdateAsync(id, request.Priority, request.Enabled, request.Value, ct); - if (result is null) return NotFound(); - return Ok(result); - } - - [HttpDelete("{apiKey}/features/{featureId}/segments/{id}")] - public async Task DeleteFeatureSegment( - string apiKey, int featureId, int id, - [FromServices] Features.FeatureSegmentService featureSegmentService, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var deleted = await featureSegmentService.DeleteAsync(id, ct); - return deleted ? NoContent() : NotFound(); - } - - // ─── Identity Segments ─────────────────────────────────────────────────── - - [HttpGet("{apiKey}/identities/{id}/segments")] - public async Task>> GetIdentitySegments( - string apiKey, int id, - [FromServices] Identities.AdminIdentityService adminIdentityService, - [FromServices] Segments.SegmentService segmentService, - [FromServices] Segments.SegmentEvaluator segmentEvaluator, - CancellationToken ct) - { - var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); - if (environment is null) return NotFound(); - - var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); - if (identity is null) return NotFound(); - - var segments = await segmentService.ListByProjectAsync(environment.ProjectId, ct); - var matching = segments - .Where(s => segmentEvaluator.Evaluate(s, identity.Traits.ToList(), identity.Identifier)) - .Select(s => new Segments.SegmentSummaryResponse(s.Id, s.Name)) - .ToList(); - - return Ok(matching); - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using MicCheck.Api.Webhooks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Environments; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class EnvironmentsController(EnvironmentService environmentService, WebhookService webhookService) : ControllerBase +{ + [HttpGet("api/v1/environments")] + public async Task>> List( + [FromQuery] int projectId, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20, + CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var all = await environmentService.ListByProjectAsync(projectId, ct); + var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(EnvironmentResponse.From).ToList(); + return Ok(new PaginatedResponse(all.Count, null, null, paged)); + } + + [HttpPost("api/v1/environments")] + public async Task> Create(CreateEnvironmentRequest request, CancellationToken ct) + { + var environment = await environmentService.CreateAsync(request.ProjectId, request.Name, ct); + return CreatedAtAction(nameof(GetByApiKey), new { apiKey = environment.ApiKey }, EnvironmentResponse.From(environment)); + } + + [HttpGet("api/v1/environment/{apiKey}")] + public async Task> GetByApiKey(string apiKey, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + return Ok(EnvironmentResponse.From(environment)); + } + + [HttpPut("api/v1/environment/{apiKey}")] + public async Task> Update(string apiKey, UpdateEnvironmentRequest request, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var updated = await environmentService.UpdateAsync(apiKey, request.Name, ct); + return Ok(EnvironmentResponse.From(updated)); + } + + [HttpDelete("api/v1/environment/{apiKey}")] + public async Task Delete(string apiKey, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + await environmentService.DeleteAsync(apiKey, ct); + return NoContent(); + } + + [HttpPost("api/v1/environment/{apiKey}/clone")] + public async Task> Clone(string apiKey, CloneEnvironmentRequest request, CancellationToken ct) + { + var source = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (source is null) return NotFound(); + + var cloned = await environmentService.CloneAsync(apiKey, request.Name, ct); + return CreatedAtAction(nameof(GetByApiKey), new { apiKey = cloned.ApiKey }, EnvironmentResponse.From(cloned)); + } + + [HttpGet("api/v1/environment/{apiKey}/webhooks")] + public async Task>> ListWebhooks(string apiKey, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var webhooks = await webhookService.ListByEnvironmentAsync(environment.Id, ct); + return Ok(webhooks.Select(WebhookResponse.From).ToList()); + } + + [HttpPost("api/v1/environment/{apiKey}/webhooks")] + public async Task> CreateWebhook( + string apiKey, CreateWebhookRequest request, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var webhook = await webhookService.CreateAsync(environment.Id, request.Url, request.Secret, request.Enabled, ct); + return CreatedAtAction(nameof(GetByApiKey), new { apiKey }, WebhookResponse.From(webhook)); + } + + [HttpPut("api/v1/environment/{apiKey}/webhook/{id}")] + public async Task> UpdateWebhook( + string apiKey, int id, CreateWebhookRequest request, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var webhook = await webhookService.FindByIdAsync(id, ct); + if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); + + var updated = await webhookService.UpdateAsync(id, request.Url, request.Secret, request.Enabled, ct); + return Ok(WebhookResponse.From(updated)); + } + + [HttpGet("api/v1/environment/{apiKey}/webhook/{id}/deliveries")] + public async Task>> ListWebhookDeliveries( + string apiKey, int id, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var webhook = await webhookService.FindByIdAsync(id, ct); + if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); + + var logs = await webhookService.ListDeliveriesAsync(id, ct); + return Ok(logs.Select(WebhookDeliveryLogResponse.From).ToList()); + } + + [HttpDelete("api/v1/environment/{apiKey}/webhook/{id}")] + public async Task DeleteWebhook(string apiKey, int id, CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var webhook = await webhookService.FindByIdAsync(id, ct); + if (webhook is null || webhook.EnvironmentId != environment.Id) return NotFound(); + + await webhookService.DeleteAsync(id, ct); + return NoContent(); + } + + [HttpGet("api/v1/environment/{apiKey}/audit-logs")] + public async Task>> ListAuditLogs( + string apiKey, + [FromServices] Audit.AuditLogQueryService auditLogQueryService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var (_, logs) = await auditLogQueryService.ListByEnvironmentAsync(environment.Id, new Audit.AuditLogFilter(), ct); + return Ok(logs.ToList()); + } + + [HttpGet("api/v1/environment/{apiKey}/identities")] + public async Task>> ListIdentities( + string apiKey, + [FromServices] Identities.AdminIdentityService adminIdentityService, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20, + CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var (total, items) = await adminIdentityService.ListAsync(environment.Id, page, pageSize, ct); + var results = items.Select(Identities.AdminIdentityResponse.From).ToList(); + return Ok(new PaginatedResponse(total, null, null, results)); + } + + [HttpPost("api/v1/environment/{apiKey}/identities")] + public async Task> CreateIdentity( + string apiKey, + [FromBody] Identities.CreateIdentityRequest request, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.CreateAsync(environment.Id, request.Identifier, ct); + if (identity is null) + return Conflict(new { error = "An identity with this identifier already exists in the environment." }); + + return CreatedAtAction(nameof(GetIdentity), new { apiKey, id = identity.Id }, + Identities.AdminIdentityResponse.From(identity)); + } + + [HttpGet("api/v1/environment/{apiKey}/identity/{id}")] + public async Task> GetIdentity( + string apiKey, int id, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + return Ok(Identities.AdminIdentityResponse.From(identity)); + } + + [HttpDelete("api/v1/environment/{apiKey}/identity/{id}")] + public async Task DeleteIdentity( + string apiKey, int id, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + + await adminIdentityService.DeleteAsync(id, ct); + return NoContent(); + } + + [HttpPut("api/v1/environment/{apiKey}/identity/{id}/trait/{key}")] + public async Task> UpsertIdentityTrait( + string apiKey, int id, string key, + [FromBody] Identities.UpsertTraitRequest request, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var result = await adminIdentityService.UpsertTraitAsync(id, environment.Id, key, request.Value, ct); + if (result is null) return NotFound(); + return Ok(result); + } + + [HttpDelete("api/v1/environment/{apiKey}/identity/{id}/trait/{key}")] + public async Task DeleteIdentityTrait( + string apiKey, int id, string key, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var deleted = await adminIdentityService.DeleteTraitAsync(id, environment.Id, key, ct); + if (!deleted) return NotFound(); + return NoContent(); + } + + [HttpGet("api/v1/environment/{apiKey}/identity/{id}/featurestates")] + public async Task>> GetIdentityFeatureStates( + string apiKey, int id, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + + var states = await adminIdentityService.GetFeatureStatesAsync(id, environment.Id, ct); + return Ok(states.Select(Features.FeatureStateResponse.From).ToList()); + } + + [HttpPut("api/v1/environment/{apiKey}/identity/{id}/featurestate/{featureId}")] + public async Task> SetIdentityFeatureState( + string apiKey, int id, int featureId, + Features.UpdateFeatureStateRequest request, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + + var state = await adminIdentityService.SetFeatureStateAsync(id, environment.Id, featureId, request.Enabled, request.Value, ct); + return Ok(Features.FeatureStateResponse.From(state)); + } + + [HttpDelete("api/v1/environment/{apiKey}/identity/{id}/featurestate/{featureId}")] + public async Task DeleteIdentityFeatureState( + string apiKey, int id, int featureId, + [FromServices] Identities.AdminIdentityService adminIdentityService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + + await adminIdentityService.DeleteFeatureStateAsync(id, environment.Id, featureId, ct); + return NoContent(); + } + + [HttpGet("api/v1/environment/{apiKey}/featurestates")] + public async Task>> ListFeatureStates( + string apiKey, + [FromServices] Features.FeatureStateService featureStateService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var states = await featureStateService.ListByEnvironmentAsync(environment.Id, ct); + return Ok(states.Select(Features.FeatureStateResponse.From).ToList()); + } + + [HttpGet("api/v1/environment/{apiKey}/featurestate/{id}")] + public async Task> GetFeatureState( + string apiKey, int id, + [FromServices] Features.FeatureStateService featureStateService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); + if (state is null) return NotFound(); + return Ok(Features.FeatureStateResponse.From(state)); + } + + [HttpPut("api/v1/environment/{apiKey}/featurestate/{id}")] + public async Task> UpdateFeatureState( + string apiKey, int id, + Features.UpdateFeatureStateRequest request, + [FromServices] Features.FeatureStateService featureStateService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); + if (state is null) return NotFound(); + + var updated = await featureStateService.UpdateAsync(id, request.Enabled, request.Value, ct); + return Ok(Features.FeatureStateResponse.From(updated)); + } + + [HttpPatch("api/v1/environment/{apiKey}/featurestate/{id}")] + public async Task> PatchFeatureState( + string apiKey, int id, + Features.PatchFeatureStateRequest request, + [FromServices] Features.FeatureStateService featureStateService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var state = await featureStateService.FindByIdAsync(id, environment.Id, ct); + if (state is null) return NotFound(); + + var updated = await featureStateService.PatchAsync(id, request.Enabled, request.Value, ct); + return Ok(Features.FeatureStateResponse.From(updated)); + } + + // ─── Feature Segments ──────────────────────────────────────────────────── + + [HttpGet("api/v1/environment/{apiKey}/feature/{featureId}/segments")] + public async Task>> ListFeatureSegments( + string apiKey, int featureId, + [FromServices] Features.FeatureSegmentService featureSegmentService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var results = await featureSegmentService.ListByFeatureAsync(featureId, environment.Id, ct); + return Ok(results); + } + + [HttpPost("api/v1/environment/{apiKey}/feature/{featureId}/segments")] + public async Task> CreateFeatureSegment( + string apiKey, int featureId, + Features.CreateFeatureSegmentRequest request, + [FromServices] Features.FeatureSegmentService featureSegmentService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + try + { + var result = await featureSegmentService.CreateAsync( + featureId, environment.Id, request.SegmentId, request.Priority, + request.Enabled, request.Value, ct); + return Ok(result); + } + catch (KeyNotFoundException ex) + { + return NotFound(new { error = ex.Message }); + } + } + + [HttpPut("api/v1/environment/{apiKey}/feature/{featureId}/segment/{id}")] + public async Task> UpdateFeatureSegment( + string apiKey, int featureId, int id, + Features.UpdateFeatureSegmentRequest request, + [FromServices] Features.FeatureSegmentService featureSegmentService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var result = await featureSegmentService.UpdateAsync(id, request.Priority, request.Enabled, request.Value, ct); + if (result is null) return NotFound(); + return Ok(result); + } + + [HttpDelete("api/v1/environment/{apiKey}/feature/{featureId}/segment/{id}")] + public async Task DeleteFeatureSegment( + string apiKey, int featureId, int id, + [FromServices] Features.FeatureSegmentService featureSegmentService, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var deleted = await featureSegmentService.DeleteAsync(id, ct); + return deleted ? NoContent() : NotFound(); + } + + // ─── Identity Segments ─────────────────────────────────────────────────── + + [HttpGet("api/v1/environment/{apiKey}/identity/{id}/segments")] + public async Task>> GetIdentitySegments( + string apiKey, int id, + [FromServices] Identities.AdminIdentityService adminIdentityService, + [FromServices] Segments.SegmentService segmentService, + [FromServices] Segments.SegmentEvaluator segmentEvaluator, + CancellationToken ct) + { + var environment = await environmentService.FindByApiKeyAsync(apiKey, ct); + if (environment is null) return NotFound(); + + var identity = await adminIdentityService.FindByIdAsync(id, environment.Id, ct); + if (identity is null) return NotFound(); + + var segments = await segmentService.ListByProjectAsync(environment.ProjectId, ct); + var matching = segments + .Where(s => segmentEvaluator.Evaluate(s, identity.Traits.ToList(), identity.Identifier)) + .Select(s => new Segments.SegmentSummaryResponse(s.Id, s.Name)) + .ToList(); + + return Ok(matching); + } +} diff --git a/src/api/MicCheck.Api/Environments/UpdateEnvironmentRequest.cs b/src/api/MicCheck.Api/Environments/UpdateEnvironmentRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/CreateFeatureRequest.cs b/src/api/MicCheck.Api/Features/CreateFeatureRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/CreateTagRequest.cs b/src/api/MicCheck.Api/Features/CreateTagRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/Feature.cs b/src/api/MicCheck.Api/Features/Feature.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs b/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs old mode 100644 new mode 100755 index 50b05a8..53798b5 --- a/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs +++ b/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs @@ -8,7 +8,8 @@ namespace MicCheck.Api.Features; public class FeatureEvaluationService( MicCheckDbContext db, SegmentEvaluator segmentEvaluator, - FlagCache flagCache) + FlagCache flagCache, + FeatureUsageMetrics usageMetrics) { public async Task> EvaluateForEnvironmentAsync( int environmentId, CancellationToken ct = default) @@ -32,6 +33,10 @@ public class FeatureEvaluationService( ).ToListAsync(ct); flagCache.Set(environmentId, results); + + foreach (var r in results) + usageMetrics.RecordEvaluation(environmentId, r.Feature.Id, r.Feature.Name); + return results; } @@ -134,6 +139,9 @@ public class FeatureEvaluationService( } } + foreach (var r in results) + usageMetrics.RecordEvaluation(environmentId, r.Feature.Id, r.Feature.Name); + return results; } } diff --git a/src/api/MicCheck.Api/Features/FeatureResponse.cs b/src/api/MicCheck.Api/Features/FeatureResponse.cs old mode 100644 new mode 100755 index 0b177d6..d8e5b2c --- a/src/api/MicCheck.Api/Features/FeatureResponse.cs +++ b/src/api/MicCheck.Api/Features/FeatureResponse.cs @@ -8,7 +8,8 @@ public record FeatureResponse( string? Description, bool DefaultEnabled, int ProjectId, - DateTimeOffset CreatedAt + DateTimeOffset CreatedAt, + IReadOnlyList Tags ) { public static FeatureResponse From(Feature feature) => new( @@ -19,5 +20,6 @@ public record FeatureResponse( feature.Description, feature.DefaultEnabled, feature.ProjectId, - feature.CreatedAt); + feature.CreatedAt, + feature.Tags.Select(TagResponse.From).ToList()); } diff --git a/src/api/MicCheck.Api/Features/FeatureSegment.cs b/src/api/MicCheck.Api/Features/FeatureSegment.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureSegmentRequest.cs b/src/api/MicCheck.Api/Features/FeatureSegmentRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureSegmentResponse.cs b/src/api/MicCheck.Api/Features/FeatureSegmentResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureSegmentService.cs b/src/api/MicCheck.Api/Features/FeatureSegmentService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureService.cs b/src/api/MicCheck.Api/Features/FeatureService.cs old mode 100644 new mode 100755 index 2113444..9dccd5e --- a/src/api/MicCheck.Api/Features/FeatureService.cs +++ b/src/api/MicCheck.Api/Features/FeatureService.cs @@ -13,13 +13,14 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web public async Task> ListByProjectAsync(int projectId, CancellationToken ct = default) { return await db.Features + .Include(f => f.Tags) .Where(f => f.ProjectId == projectId) .ToListAsync(ct); } public async Task FindByIdAsync(int id, CancellationToken ct = default) { - return await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct); + return await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == id, ct); } public async Task CreateAsync( @@ -80,7 +81,7 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web public async Task UpdateAsync( int id, string name, string? description, CancellationToken ct = default) { - var feature = await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct) + var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == id, ct) ?? throw new KeyNotFoundException($"Feature {id} not found."); var before = new { feature.Name, feature.Description }; @@ -101,6 +102,40 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web return feature; } + public async Task AssignTagAsync(int featureId, int tagId, CancellationToken ct = default) + { + var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == featureId, ct) + ?? throw new KeyNotFoundException($"Feature {featureId} not found."); + var tag = await db.Tags.FirstOrDefaultAsync(t => t.Id == tagId, ct) + ?? throw new KeyNotFoundException($"Tag {tagId} not found."); + + if (tag.ProjectId != feature.ProjectId) + throw new DomainException("Tag does not belong to the feature's project."); + + if (feature.Tags.All(t => t.Id != tagId)) + { + feature.Tags.Add(tag); + await db.SaveChangesAsync(ct); + } + + return feature; + } + + public async Task RemoveTagAsync(int featureId, int tagId, CancellationToken ct = default) + { + var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == featureId, ct) + ?? throw new KeyNotFoundException($"Feature {featureId} not found."); + + var tag = feature.Tags.FirstOrDefault(t => t.Id == tagId); + if (tag is not null) + { + feature.Tags.Remove(tag); + await db.SaveChangesAsync(ct); + } + + return feature; + } + public async Task DeleteAsync(int id, CancellationToken ct = default) { var feature = await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct); diff --git a/src/api/MicCheck.Api/Features/FeatureState.cs b/src/api/MicCheck.Api/Features/FeatureState.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureStateResponse.cs b/src/api/MicCheck.Api/Features/FeatureStateResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureStateResult.cs b/src/api/MicCheck.Api/Features/FeatureStateResult.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureStateService.cs b/src/api/MicCheck.Api/Features/FeatureStateService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureSummaryResponse.cs b/src/api/MicCheck.Api/Features/FeatureSummaryResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs b/src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs new file mode 100644 index 0000000..370437d --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Features; + +public record struct FeatureUsageBucketKey(int EnvironmentId, int FeatureId, string FeatureName, DateOnly UsageDate); diff --git a/src/api/MicCheck.Api/Features/FeatureUsageController.cs b/src/api/MicCheck.Api/Features/FeatureUsageController.cs new file mode 100644 index 0000000..82c9f37 --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageController.cs @@ -0,0 +1,32 @@ +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; +using Microsoft.Extensions.Caching.Memory; + +namespace MicCheck.Api.Features; + +[ApiController] +[Route("api/v1/environment/{environmentId}/usage")] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class FeatureUsageController(FeatureUsageQueryService queryService, IMemoryCache cache) : ControllerBase +{ + [HttpGet] + public async Task> GetDashboardUsage( + int environmentId, + [FromQuery] int days = 14, + CancellationToken ct = default) + { + days = Math.Clamp(days, 1, 90); + var cacheKey = $"usage-dashboard:{environmentId}:{days}"; + + if (cache.TryGetValue(cacheKey, out DashboardUsageResponse? cached)) + return Ok(cached); + + var result = await queryService.GetDashboardUsageAsync(environmentId, days, ct); + + cache.Set(cacheKey, result, TimeSpan.FromSeconds(180)); + return Ok(result); + } +} diff --git a/src/api/MicCheck.Api/Features/FeatureUsageDaily.cs b/src/api/MicCheck.Api/Features/FeatureUsageDaily.cs new file mode 100644 index 0000000..30ed719 --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageDaily.cs @@ -0,0 +1,12 @@ +namespace MicCheck.Api.Features; + +public class FeatureUsageDaily +{ + public int Id { get; init; } + public int EnvironmentId { get; init; } + public int FeatureId { get; init; } + public required string FeatureName { get; set; } + public DateOnly UsageDate { get; init; } + public long Count { get; set; } + public DateTimeOffset UpdatedAt { get; set; } +} diff --git a/src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs b/src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs new file mode 100644 index 0000000..6562d40 --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs @@ -0,0 +1,60 @@ +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Features; + +public class FeatureUsageFlushBackgroundService( + FeatureUsageMetrics metrics, + IServiceScopeFactory scopeFactory, + ILogger logger) : BackgroundService +{ + private static readonly TimeSpan FlushInterval = TimeSpan.FromSeconds(30); + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + using var timer = new PeriodicTimer(FlushInterval); + while (await timer.WaitForNextTickAsync(stoppingToken)) + { + await FlushAsync(stoppingToken); + } + } + + public override async Task StopAsync(CancellationToken cancellationToken) + { + await base.StopAsync(cancellationToken); + await FlushAsync(CancellationToken.None); + } + + private async Task FlushAsync(CancellationToken ct) + { + var deltas = metrics.DrainAccumulated(); + if (deltas.Count == 0) + return; + + var updatedAt = DateTimeOffset.UtcNow; + + try + { + await using var scope = scopeFactory.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + foreach (var (key, count) in deltas) + { + await db.Database.ExecuteSqlAsync( + $""" + INSERT INTO "FeatureUsageDaily" ("EnvironmentId", "FeatureId", "FeatureName", "UsageDate", "Count", "UpdatedAt") + VALUES ({key.EnvironmentId}, {key.FeatureId}, {key.FeatureName}, {key.UsageDate}, {count}, {updatedAt}) + ON CONFLICT ("EnvironmentId", "FeatureId", "UsageDate") + DO UPDATE SET "Count" = "FeatureUsageDaily"."Count" + EXCLUDED."Count", + "FeatureName" = EXCLUDED."FeatureName", + "UpdatedAt" = EXCLUDED."UpdatedAt" + """, + ct); + } + } + catch (Exception ex) + { + logger.LogError(ex, "Failed to flush feature usage data ({BucketCount} buckets)", deltas.Count); + } + } +} diff --git a/src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs b/src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs new file mode 100644 index 0000000..fd44b4b --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs @@ -0,0 +1,35 @@ +using System.Collections.Concurrent; +using System.Diagnostics.Metrics; + +namespace MicCheck.Api.Features; + +public class FeatureUsageMetrics : IDisposable +{ + private readonly Meter _meter; + private readonly Counter _evaluationCounter; + private ConcurrentDictionary _accumulator = new(); + + public FeatureUsageMetrics(IMeterFactory meterFactory) + { + _meter = meterFactory.Create("MicCheck.FeatureUsage"); + _evaluationCounter = _meter.CreateCounter("miccheck.feature.evaluations", description: "Number of feature flag evaluations"); + } + + public void RecordEvaluation(int environmentId, int featureId, string featureName) + { + _evaluationCounter.Add(1, + new KeyValuePair("environment.id", environmentId), + new KeyValuePair("feature.id", featureId)); + + var key = new FeatureUsageBucketKey(environmentId, featureId, featureName, DateOnly.FromDateTime(DateTime.UtcNow)); + _accumulator.AddOrUpdate(key, 1L, (_, existing) => existing + 1); + } + + public IReadOnlyDictionary DrainAccumulated() + { + var drained = Interlocked.Exchange(ref _accumulator, new ConcurrentDictionary()); + return drained; + } + + public void Dispose() => _meter.Dispose(); +} diff --git a/src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs b/src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs new file mode 100644 index 0000000..feb3373 --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs @@ -0,0 +1,42 @@ +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Features; + +public class FeatureUsageQueryService(MicCheckDbContext db) +{ + public async Task GetDashboardUsageAsync(int environmentId, int days, CancellationToken ct = default) + { + var today = DateOnly.FromDateTime(DateTime.UtcNow); + var windowStart = today.AddDays(-days); + var yesterday = today.AddDays(-1); + + var rows = await db.FeatureUsageDaily + .Where(u => u.EnvironmentId == environmentId && u.UsageDate >= windowStart) + .ToListAsync(ct); + + var topFeaturesLastDay = rows + .Where(u => u.UsageDate >= yesterday) + .GroupBy(u => new { u.FeatureId, u.FeatureName }) + .Select(g => new TopFeatureUsage(g.Key.FeatureId, g.Key.FeatureName, g.Sum(u => u.Count))) + .OrderByDescending(t => t.Count) + .Take(10) + .ToList(); + + var dailyUsage = rows + .GroupBy(u => u.UsageDate) + .OrderBy(g => g.Key) + .Select(g => + { + var features = g + .GroupBy(u => new { u.FeatureId, u.FeatureName }) + .Select(fg => new TopFeatureUsage(fg.Key.FeatureId, fg.Key.FeatureName, fg.Sum(u => u.Count))) + .OrderByDescending(f => f.Count) + .ToList(); + return new DailyUsage(g.Key, features.Sum(f => f.Count), features); + }) + .ToList(); + + return new DashboardUsageResponse(topFeaturesLastDay, dailyUsage); + } +} diff --git a/src/api/MicCheck.Api/Features/FeatureUsageResponses.cs b/src/api/MicCheck.Api/Features/FeatureUsageResponses.cs new file mode 100644 index 0000000..201d8b5 --- /dev/null +++ b/src/api/MicCheck.Api/Features/FeatureUsageResponses.cs @@ -0,0 +1,9 @@ +namespace MicCheck.Api.Features; + +public record TopFeatureUsage(int FeatureId, string FeatureName, long Count); + +public record DailyUsage(DateOnly Date, long TotalCount, IReadOnlyList Features); + +public record DashboardUsageResponse( + IReadOnlyList TopFeaturesLastDay, + IReadOnlyList DailyUsage); diff --git a/src/api/MicCheck.Api/Features/FeaturesController.cs b/src/api/MicCheck.Api/Features/FeaturesController.cs old mode 100644 new mode 100755 index bfb6a51..21b14c1 --- a/src/api/MicCheck.Api/Features/FeaturesController.cs +++ b/src/api/MicCheck.Api/Features/FeaturesController.cs @@ -1,88 +1,117 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Features; - -[ApiController] -[Route("api/v1/projects/{projectId}/features")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class FeaturesController(FeatureService featureService) : ControllerBase -{ - [HttpGet] - public async Task>> List( - int projectId, - [FromQuery] int page = 1, - [FromQuery] int pageSize = 20, - CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var all = await featureService.ListByProjectAsync(projectId, ct); - var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(FeatureResponse.From).ToList(); - return Ok(new PaginatedResponse(all.Count, null, null, paged)); - } - - [HttpPost] - public async Task> Create( - int projectId, CreateFeatureRequest request, CancellationToken ct) - { - try - { - var feature = await featureService.CreateAsync( - projectId, request.Name, request.Type, request.InitialValue, request.Description, ct); - - return CreatedAtAction(nameof(GetById), new { projectId, id = feature.Id }, FeatureResponse.From(feature)); - } - catch (DomainException ex) - { - return BadRequest(new { error = ex.Message }); - } - } - - [HttpGet("{id}")] - public async Task> GetById(int projectId, int id, CancellationToken ct) - { - var feature = await featureService.FindByIdAsync(id, ct); - if (feature is null || feature.ProjectId != projectId) return NotFound(); - return Ok(FeatureResponse.From(feature)); - } - - [HttpPut("{id}")] - public async Task> Update( - int projectId, int id, UpdateFeatureRequest request, CancellationToken ct) - { - var feature = await featureService.FindByIdAsync(id, ct); - if (feature is null || feature.ProjectId != projectId) return NotFound(); - - var updated = await featureService.UpdateAsync(id, request.Name, request.Description, ct); - return Ok(FeatureResponse.From(updated)); - } - - [HttpPatch("{id}")] - public async Task> Patch( - int projectId, int id, PatchFeatureRequest request, CancellationToken ct) - { - var feature = await featureService.FindByIdAsync(id, ct); - if (feature is null || feature.ProjectId != projectId) return NotFound(); - - if (request.Name is not null) feature.Name = request.Name; - if (request.Description is not null) feature.Description = request.Description; - if (request.DefaultEnabled.HasValue) feature.DefaultEnabled = request.DefaultEnabled.Value; - - var updated = await featureService.UpdateAsync(id, feature.Name, feature.Description, ct); - return Ok(FeatureResponse.From(updated)); - } - - [HttpDelete("{id}")] - public async Task Delete(int projectId, int id, CancellationToken ct) - { - var feature = await featureService.FindByIdAsync(id, ct); - if (feature is null || feature.ProjectId != projectId) return NotFound(); - - await featureService.DeleteAsync(id, ct); - return NoContent(); - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Features; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class FeaturesController(FeatureService featureService) : ControllerBase +{ + [HttpGet("api/v1/project/{projectId}/features")] + public async Task>> List( + int projectId, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20, + CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var all = await featureService.ListByProjectAsync(projectId, ct); + var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(FeatureResponse.From).ToList(); + return Ok(new PaginatedResponse(all.Count, null, null, paged)); + } + + [HttpPost("api/v1/project/{projectId}/features")] + public async Task> Create( + int projectId, CreateFeatureRequest request, CancellationToken ct) + { + try + { + var feature = await featureService.CreateAsync(projectId, request.Name, request.Type, request.InitialValue, request.Description, ct); + + return CreatedAtAction(nameof(GetById), new { projectId, id = feature.Id }, FeatureResponse.From(feature)); + } + catch (DomainException ex) + { + return BadRequest(new { error = ex.Message }); + } + } + + [HttpGet("api/v1/project/{projectId}/feature/{id}")] + public async Task> GetById(int projectId, int id, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + return Ok(FeatureResponse.From(feature)); + } + + [HttpPut("api/v1/project/{projectId}/feature/{id}")] + public async Task> Update( + int projectId, int id, UpdateFeatureRequest request, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + + var updated = await featureService.UpdateAsync(id, request.Name, request.Description, ct); + return Ok(FeatureResponse.From(updated)); + } + + [HttpPatch("api/v1/project/{projectId}/feature/{id}")] + public async Task> Patch( + int projectId, int id, PatchFeatureRequest request, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + + if (request.Name is not null) feature.Name = request.Name; + if (request.Description is not null) feature.Description = request.Description; + if (request.DefaultEnabled.HasValue) feature.DefaultEnabled = request.DefaultEnabled.Value; + + var updated = await featureService.UpdateAsync(id, feature.Name, feature.Description, ct); + return Ok(FeatureResponse.From(updated)); + } + + [HttpDelete("api/v1/project/{projectId}/feature/{id}")] + public async Task Delete(int projectId, int id, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + + await featureService.DeleteAsync(id, ct); + return NoContent(); + } + + [HttpPut("api/v1/project/{projectId}/feature/{id}/tag/{tagId}")] + public async Task> AssignTag(int projectId, int id, int tagId, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + + try + { + var updated = await featureService.AssignTagAsync(id, tagId, ct); + return Ok(FeatureResponse.From(updated)); + } + catch (KeyNotFoundException) + { + return NotFound(); + } + catch (DomainException ex) + { + return BadRequest(new { error = ex.Message }); + } + } + + [HttpDelete("api/v1/project/{projectId}/feature/{id}/tag/{tagId}")] + public async Task> RemoveTag(int projectId, int id, int tagId, CancellationToken ct) + { + var feature = await featureService.FindByIdAsync(id, ct); + if (feature is null || feature.ProjectId != projectId) return NotFound(); + + var updated = await featureService.RemoveTagAsync(id, tagId, ct); + return Ok(FeatureResponse.From(updated)); + } +} diff --git a/src/api/MicCheck.Api/Features/FlagCache.cs b/src/api/MicCheck.Api/Features/FlagCache.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/FlagResponse.cs b/src/api/MicCheck.Api/Features/FlagResponse.cs old mode 100644 new mode 100755 index 06d6c6a..e2cd508 --- a/src/api/MicCheck.Api/Features/FlagResponse.cs +++ b/src/api/MicCheck.Api/Features/FlagResponse.cs @@ -1,14 +1,6 @@ namespace MicCheck.Api.Features; -public record FlagResponse( - int Id, - FeatureSummaryResponse Feature, - bool Enabled, - string? FeatureStateValue) +public record FlagResponse(int Id, FeatureSummaryResponse Feature, bool Enabled, string? FeatureStateValue) { - public static FlagResponse From(FeatureStateResult result) => new( - result.Feature.Id, - FeatureSummaryResponse.From(result.Feature), - result.Enabled, - result.Value); + public static FlagResponse From(FeatureStateResult result) => new(result.Feature.Id, FeatureSummaryResponse.From(result.Feature), result.Enabled, result.Value); } diff --git a/src/api/MicCheck.Api/Features/FlagsController.cs b/src/api/MicCheck.Api/Features/FlagsController.cs old mode 100644 new mode 100755 index 303aecf..088bb7f --- a/src/api/MicCheck.Api/Features/FlagsController.cs +++ b/src/api/MicCheck.Api/Features/FlagsController.cs @@ -1,19 +1,19 @@ -using MicCheck.Api.Authorization; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace MicCheck.Api.Features; - -[ApiController] -[Route("api/v1/flags")] -[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] -public class FlagsController(FeatureEvaluationService featureEvaluationService) : ControllerBase -{ - [HttpGet] - public async Task>> GetAll(CancellationToken ct) - { - var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value); - var results = await featureEvaluationService.EvaluateForEnvironmentAsync(environmentId, ct); - return Ok(results.Select(FlagResponse.From).ToList()); - } -} +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace MicCheck.Api.Features; + +[ApiController] +[Route("api/v1/flags")] +[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] +public class FlagsController(FeatureEvaluationService featureEvaluationService) : ControllerBase +{ + [HttpGet] + public async Task>> GetAll(CancellationToken ct) + { + var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value); + var results = await featureEvaluationService.EvaluateForEnvironmentAsync(environmentId, ct); + return Ok(results.Select(FlagResponse.From).ToList()); + } +} diff --git a/src/api/MicCheck.Api/Features/PatchFeatureRequest.cs b/src/api/MicCheck.Api/Features/PatchFeatureRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/Tag.cs b/src/api/MicCheck.Api/Features/Tag.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/TagResponse.cs b/src/api/MicCheck.Api/Features/TagResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/TagService.cs b/src/api/MicCheck.Api/Features/TagService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/TagsController.cs b/src/api/MicCheck.Api/Features/TagsController.cs old mode 100644 new mode 100755 index b41cc62..709bcb4 --- a/src/api/MicCheck.Api/Features/TagsController.cs +++ b/src/api/MicCheck.Api/Features/TagsController.cs @@ -1,37 +1,36 @@ -using MicCheck.Api.Authorization; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Features; - -[ApiController] -[Route("api/v1/projects/{projectId}/tags")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class TagsController(TagService tagService) : ControllerBase -{ - [HttpGet] - public async Task>> List(int projectId, CancellationToken ct) - { - var tags = await tagService.ListByProjectAsync(projectId, ct); - return Ok(tags.Select(TagResponse.From).ToList()); - } - - [HttpPost] - public async Task> Create(int projectId, CreateTagRequest request, CancellationToken ct) - { - var tag = await tagService.CreateAsync(projectId, request.Label, request.Color, ct); - return CreatedAtAction(nameof(List), new { projectId }, TagResponse.From(tag)); - } - - [HttpDelete("{id}")] - public async Task Delete(int projectId, int id, CancellationToken ct) - { - var tag = await tagService.FindByIdAsync(id, ct); - if (tag is null || tag.ProjectId != projectId) return NotFound(); - - await tagService.DeleteAsync(id, ct); - return NoContent(); - } -} +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Features; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class TagsController(TagService tagService) : ControllerBase +{ + [HttpGet("api/v1/project/{projectId}/tags")] + public async Task>> List(int projectId, CancellationToken ct) + { + var tags = await tagService.ListByProjectAsync(projectId, ct); + return Ok(tags.Select(TagResponse.From).ToList()); + } + + [HttpPost("api/v1/project/{projectId}/tags")] + public async Task> Create(int projectId, CreateTagRequest request, CancellationToken ct) + { + var tag = await tagService.CreateAsync(projectId, request.Label, request.Color, ct); + return CreatedAtAction(nameof(List), new { projectId }, TagResponse.From(tag)); + } + + [HttpDelete("api/v1/project/{projectId}/tag/{id}")] + public async Task Delete(int projectId, int id, CancellationToken ct) + { + var tag = await tagService.FindByIdAsync(id, ct); + if (tag is null || tag.ProjectId != projectId) return NotFound(); + + await tagService.DeleteAsync(id, ct); + return NoContent(); + } +} diff --git a/src/api/MicCheck.Api/Features/UpdateFeatureRequest.cs b/src/api/MicCheck.Api/Features/UpdateFeatureRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Features/UpdateFeatureStateRequest.cs b/src/api/MicCheck.Api/Features/UpdateFeatureStateRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/AdminIdentityResponse.cs b/src/api/MicCheck.Api/Identities/AdminIdentityResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/AdminIdentityService.cs b/src/api/MicCheck.Api/Identities/AdminIdentityService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/CreateIdentityRequest.cs b/src/api/MicCheck.Api/Identities/CreateIdentityRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/IdentitiesController.cs b/src/api/MicCheck.Api/Identities/IdentitiesController.cs old mode 100644 new mode 100755 index 08b0534..8475aa9 --- a/src/api/MicCheck.Api/Identities/IdentitiesController.cs +++ b/src/api/MicCheck.Api/Identities/IdentitiesController.cs @@ -1,47 +1,47 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Features; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace MicCheck.Api.Identities; - -[ApiController] -[Route("api/v1/identities")] -[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] -public class IdentitiesController( - FeatureEvaluationService featureEvaluationService, - IdentityResolutionService identityResolutionService) : ControllerBase -{ - [HttpGet] - public async Task> GetByIdentifier( - [FromQuery] string identifier, CancellationToken ct) - { - if (string.IsNullOrWhiteSpace(identifier)) - return BadRequest("identifier query parameter is required."); - - var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value!); - - var identity = await identityResolutionService.ResolveAsync(environmentId, identifier, null, ct); - var flags = await featureEvaluationService.EvaluateForIdentityAsync(environmentId, identifier, null, ct); - - return Ok(new IdentityResponse( - identity.Traits.Select(TraitResponse.From).ToList(), - flags.Select(FlagResponse.From).ToList())); - } - - [HttpPost] - public async Task> Identify( - [FromBody] IdentityRequest request, CancellationToken ct) - { - var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value!); - - var identity = await identityResolutionService.ResolveAsync( - environmentId, request.Identifier, request.Traits, ct); - var flags = await featureEvaluationService.EvaluateForIdentityAsync( - environmentId, request.Identifier, request.Traits, ct); - - return Ok(new IdentityResponse( - identity.Traits.Select(TraitResponse.From).ToList(), - flags.Select(FlagResponse.From).ToList())); - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Features; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace MicCheck.Api.Identities; + +[ApiController] +[Route("api/v1/identity")] +[Authorize(Policy = AuthorizationPolicies.FlagsApiAccess)] +public class IdentitiesController( + FeatureEvaluationService featureEvaluationService, + IdentityResolutionService identityResolutionService) : ControllerBase +{ + [HttpGet] + public async Task> GetByIdentifier( + [FromQuery] string identifier, CancellationToken ct) + { + if (string.IsNullOrWhiteSpace(identifier)) + return BadRequest("identifier query parameter is required."); + + var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value!); + + var identity = await identityResolutionService.ResolveAsync(environmentId, identifier, null, ct); + var flags = await featureEvaluationService.EvaluateForIdentityAsync(environmentId, identifier, null, ct); + + return Ok(new IdentityResponse( + identity.Traits.Select(TraitResponse.From).ToList(), + flags.Select(FlagResponse.From).ToList())); + } + + [HttpPost] + public async Task> Identify( + [FromBody] IdentityRequest request, CancellationToken ct) + { + var environmentId = int.Parse(User.FindFirst("EnvironmentId")!.Value!); + + var identity = await identityResolutionService.ResolveAsync( + environmentId, request.Identifier, request.Traits, ct); + var flags = await featureEvaluationService.EvaluateForIdentityAsync( + environmentId, request.Identifier, request.Traits, ct); + + return Ok(new IdentityResponse( + identity.Traits.Select(TraitResponse.From).ToList(), + flags.Select(FlagResponse.From).ToList())); + } +} diff --git a/src/api/MicCheck.Api/Identities/Identity.cs b/src/api/MicCheck.Api/Identities/Identity.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/IdentityRequest.cs b/src/api/MicCheck.Api/Identities/IdentityRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/IdentityResolutionService.cs b/src/api/MicCheck.Api/Identities/IdentityResolutionService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/IdentityResponse.cs b/src/api/MicCheck.Api/Identities/IdentityResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/IdentityTrait.cs b/src/api/MicCheck.Api/Identities/IdentityTrait.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/TraitInput.cs b/src/api/MicCheck.Api/Identities/TraitInput.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/TraitResponse.cs b/src/api/MicCheck.Api/Identities/TraitResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Identities/UpsertTraitRequest.cs b/src/api/MicCheck.Api/Identities/UpsertTraitRequest.cs old mode 100644 new mode 100755 index 5dfa49d..60b9a32 --- a/src/api/MicCheck.Api/Identities/UpsertTraitRequest.cs +++ b/src/api/MicCheck.Api/Identities/UpsertTraitRequest.cs @@ -1,3 +1,3 @@ namespace MicCheck.Api.Identities; -public record UpsertTraitRequest(string Key, string Value); +public record UpsertTraitRequest(string Value); diff --git a/src/api/MicCheck.Api/MicCheck.Api.csproj b/src/api/MicCheck.Api/MicCheck.Api.csproj old mode 100644 new mode 100755 index 28399d3..b650ca2 --- a/src/api/MicCheck.Api/MicCheck.Api.csproj +++ b/src/api/MicCheck.Api/MicCheck.Api.csproj @@ -1,26 +1,31 @@ - - - - net10.0 - enable - enable - latest - true - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - + + + + net10.0 + enable + enable + latest + true + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.Designer.cs b/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.Designer.cs old mode 100644 new mode 100755 index a271252..f4d7a24 --- a/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.Designer.cs +++ b/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.Designer.cs @@ -1,895 +1,895 @@ -// -using System; -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace MicCheck.Api.Migrations -{ - [DbContext(typeof(MicCheckDbContext))] - [Migration("20260408214714_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Prefix") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.HasKey("Id"); - - b.HasIndex("Key") - .IsUnique(); - - b.HasIndex("OrganizationId"); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ActorUserId") - .HasColumnType("integer"); - - b.Property("Changes") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ResourceType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId", "CreatedAt"); - - b.ToTable("AuditLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.Authorization.UserProjectPermission", b => - { - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("IsAdmin") - .HasColumnType("boolean"); - - b.Property("Permissions") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("UserId", "ProjectId"); - - b.ToTable("UserProjectPermissions"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiKey") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ApiKey") - .IsUnique(); - - b.HasIndex("ProjectId"); - - b.ToTable("Environments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DefaultEnabled") - .HasColumnType("boolean"); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("InitialValue") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("character varying(150)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId", "Name") - .IsUnique(); - - b.ToTable("Features"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("Priority") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("FeatureSegments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("FeatureSegmentId") - .HasColumnType("integer"); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Value") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Version") - .IsConcurrencyToken() - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.HasIndex("FeatureSegmentId") - .IsUnique(); - - b.HasIndex("IdentityId"); - - b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") - .IsUnique(); - - b.ToTable("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Color") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("Identifier") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId", "Identifier") - .IsUnique(); - - b.ToTable("Identities"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("ValueType") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("IdentityId", "Key") - .IsUnique(); - - b.ToTable("IdentityTraits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.HasKey("Id"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("integer"); - - b.HasKey("OrganizationId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("OrganizationUsers"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HideDisabledFlags") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId"); - - b.ToTable("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Operator") - .HasColumnType("integer"); - - b.Property("Property") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("RuleId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.HasKey("Id"); - - b.HasIndex("RuleId"); - - b.ToTable("SegmentConditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ParentRuleId") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ParentRuleId"); - - b.HasIndex("SegmentId"); - - b.ToTable("SegmentRules"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("Token") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("IsTwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("LastLoginAt") - .HasColumnType("timestamp with time zone"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("integer"); - - b.Property("Secret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.ToTable("Webhooks"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Duration") - .HasColumnType("interval"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PayloadJson") - .IsRequired() - .HasColumnType("text"); - - b.Property("ResponseBody") - .HasColumnType("text"); - - b.Property("ResponseStatusCode") - .HasColumnType("integer"); - - b.Property("Success") - .HasColumnType("boolean"); - - b.Property("WebhookId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("WebhookId"); - - b.ToTable("WebhookDeliveryLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("ApiKeys") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Environments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Features") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.HasOne("MicCheck.Api.Environments.Environment", null) - .WithMany("FeatureStates") - .HasForeignKey("EnvironmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("FeatureStates") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.FeatureSegment", null) - .WithOne("FeatureState") - .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("FeatureStateOverrides") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("Tags") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("Traits") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Members") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Users.User", null) - .WithMany("Organizations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Projects") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Segments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("Conditions") - .HasForeignKey("RuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("ChildRules") - .HasForeignKey("ParentRuleId") - .OnDelete(DeleteBehavior.NoAction); - - b.HasOne("MicCheck.Api.Segments.Segment", null) - .WithMany("Rules") - .HasForeignKey("SegmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.HasOne("MicCheck.Api.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Navigation("FeatureStates"); - - b.Navigation("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Navigation("FeatureState"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Navigation("FeatureStateOverrides"); - - b.Navigation("Traits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Navigation("ApiKeys"); - - b.Navigation("Members"); - - b.Navigation("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Navigation("Environments"); - - b.Navigation("Features"); - - b.Navigation("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Navigation("Rules"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Navigation("ChildRules"); - - b.Navigation("Conditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Navigation("Organizations"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260408214714_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("Tags") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", null) + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.cs b/src/api/MicCheck.Api/Migrations/20260408214714_InitialCreate.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.Designer.cs b/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.Designer.cs old mode 100644 new mode 100755 index aefaf0e..e7dc7fa --- a/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.Designer.cs +++ b/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.Designer.cs @@ -1,898 +1,898 @@ -// -using System; -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace MicCheck.Api.Migrations -{ - [DbContext(typeof(MicCheckDbContext))] - [Migration("20260410175950_AddWebhookDeliveryAttemptNumber")] - partial class AddWebhookDeliveryAttemptNumber - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Prefix") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.HasKey("Id"); - - b.HasIndex("Key") - .IsUnique(); - - b.HasIndex("OrganizationId"); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ActorUserId") - .HasColumnType("integer"); - - b.Property("Changes") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ResourceType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId", "CreatedAt"); - - b.ToTable("AuditLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.Authorization.UserProjectPermission", b => - { - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("IsAdmin") - .HasColumnType("boolean"); - - b.Property("Permissions") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("UserId", "ProjectId"); - - b.ToTable("UserProjectPermissions"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiKey") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ApiKey") - .IsUnique(); - - b.HasIndex("ProjectId"); - - b.ToTable("Environments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DefaultEnabled") - .HasColumnType("boolean"); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("InitialValue") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("character varying(150)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId", "Name") - .IsUnique(); - - b.ToTable("Features"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("Priority") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("FeatureSegments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("FeatureSegmentId") - .HasColumnType("integer"); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Value") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Version") - .IsConcurrencyToken() - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.HasIndex("FeatureSegmentId") - .IsUnique(); - - b.HasIndex("IdentityId"); - - b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") - .IsUnique(); - - b.ToTable("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Color") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("Identifier") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId", "Identifier") - .IsUnique(); - - b.ToTable("Identities"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("ValueType") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("IdentityId", "Key") - .IsUnique(); - - b.ToTable("IdentityTraits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.HasKey("Id"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("integer"); - - b.HasKey("OrganizationId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("OrganizationUsers"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HideDisabledFlags") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId"); - - b.ToTable("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Operator") - .HasColumnType("integer"); - - b.Property("Property") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("RuleId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.HasKey("Id"); - - b.HasIndex("RuleId"); - - b.ToTable("SegmentConditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ParentRuleId") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ParentRuleId"); - - b.HasIndex("SegmentId"); - - b.ToTable("SegmentRules"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("Token") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("IsTwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("LastLoginAt") - .HasColumnType("timestamp with time zone"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("integer"); - - b.Property("Secret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.ToTable("Webhooks"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AttemptNumber") - .HasColumnType("integer"); - - b.Property("AttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Duration") - .HasColumnType("interval"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PayloadJson") - .IsRequired() - .HasColumnType("text"); - - b.Property("ResponseBody") - .HasColumnType("text"); - - b.Property("ResponseStatusCode") - .HasColumnType("integer"); - - b.Property("Success") - .HasColumnType("boolean"); - - b.Property("WebhookId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("WebhookId"); - - b.ToTable("WebhookDeliveryLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("ApiKeys") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Environments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Features") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.HasOne("MicCheck.Api.Environments.Environment", null) - .WithMany("FeatureStates") - .HasForeignKey("EnvironmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("FeatureStates") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.FeatureSegment", null) - .WithOne("FeatureState") - .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("FeatureStateOverrides") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("Tags") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("Traits") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Members") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Users.User", null) - .WithMany("Organizations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Projects") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Segments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("Conditions") - .HasForeignKey("RuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("ChildRules") - .HasForeignKey("ParentRuleId") - .OnDelete(DeleteBehavior.NoAction); - - b.HasOne("MicCheck.Api.Segments.Segment", null) - .WithMany("Rules") - .HasForeignKey("SegmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.HasOne("MicCheck.Api.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Navigation("FeatureStates"); - - b.Navigation("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Navigation("FeatureState"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Navigation("FeatureStateOverrides"); - - b.Navigation("Traits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Navigation("ApiKeys"); - - b.Navigation("Members"); - - b.Navigation("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Navigation("Environments"); - - b.Navigation("Features"); - - b.Navigation("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Navigation("Rules"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Navigation("ChildRules"); - - b.Navigation("Conditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Navigation("Organizations"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260410175950_AddWebhookDeliveryAttemptNumber")] + partial class AddWebhookDeliveryAttemptNumber + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("Tags") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", null) + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.cs b/src/api/MicCheck.Api/Migrations/20260410175950_AddWebhookDeliveryAttemptNumber.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.Designer.cs b/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.Designer.cs old mode 100644 new mode 100755 index 013f6e4..7a5f6d8 --- a/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.Designer.cs +++ b/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.Designer.cs @@ -1,926 +1,926 @@ -// -using System; -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace MicCheck.Api.Migrations -{ - [DbContext(typeof(MicCheckDbContext))] - [Migration("20260414203426_FixTagRelationships")] - partial class FixTagRelationships - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("FeatureTags", b => - { - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("TagsId") - .HasColumnType("integer"); - - b.HasKey("FeatureId", "TagsId"); - - b.HasIndex("TagsId"); - - b.ToTable("FeatureTags"); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Prefix") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.HasKey("Id"); - - b.HasIndex("Key") - .IsUnique(); - - b.HasIndex("OrganizationId"); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ActorUserId") - .HasColumnType("integer"); - - b.Property("Changes") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ResourceType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId", "CreatedAt"); - - b.ToTable("AuditLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.Authorization.UserProjectPermission", b => - { - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("IsAdmin") - .HasColumnType("boolean"); - - b.Property("Permissions") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("UserId", "ProjectId"); - - b.ToTable("UserProjectPermissions"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiKey") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ApiKey") - .IsUnique(); - - b.HasIndex("ProjectId"); - - b.ToTable("Environments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DefaultEnabled") - .HasColumnType("boolean"); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("InitialValue") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("character varying(150)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId", "Name") - .IsUnique(); - - b.ToTable("Features"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("Priority") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("FeatureSegments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("FeatureSegmentId") - .HasColumnType("integer"); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Value") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Version") - .IsConcurrencyToken() - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.HasIndex("FeatureSegmentId") - .IsUnique(); - - b.HasIndex("IdentityId"); - - b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") - .IsUnique(); - - b.ToTable("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Color") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("Identifier") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId", "Identifier") - .IsUnique(); - - b.ToTable("Identities"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("ValueType") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("IdentityId", "Key") - .IsUnique(); - - b.ToTable("IdentityTraits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.HasKey("Id"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("integer"); - - b.HasKey("OrganizationId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("OrganizationUsers"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HideDisabledFlags") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId"); - - b.ToTable("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Operator") - .HasColumnType("integer"); - - b.Property("Property") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("RuleId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.HasKey("Id"); - - b.HasIndex("RuleId"); - - b.ToTable("SegmentConditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ParentRuleId") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ParentRuleId"); - - b.HasIndex("SegmentId"); - - b.ToTable("SegmentRules"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("Token") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("IsTwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("LastLoginAt") - .HasColumnType("timestamp with time zone"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("integer"); - - b.Property("Secret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.ToTable("Webhooks"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AttemptNumber") - .HasColumnType("integer"); - - b.Property("AttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Duration") - .HasColumnType("interval"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PayloadJson") - .IsRequired() - .HasColumnType("text"); - - b.Property("ResponseBody") - .HasColumnType("text"); - - b.Property("ResponseStatusCode") - .HasColumnType("integer"); - - b.Property("Success") - .HasColumnType("boolean"); - - b.Property("WebhookId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("WebhookId"); - - b.ToTable("WebhookDeliveryLogs"); - }); - - modelBuilder.Entity("FeatureTags", b => - { - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany() - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Tag", null) - .WithMany() - .HasForeignKey("TagsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("ApiKeys") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Environments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Features") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.HasOne("MicCheck.Api.Environments.Environment", null) - .WithMany("FeatureStates") - .HasForeignKey("EnvironmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("FeatureStates") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.FeatureSegment", null) - .WithOne("FeatureState") - .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("FeatureStateOverrides") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("Traits") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Members") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Users.User", null) - .WithMany("Organizations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Projects") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Segments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("Conditions") - .HasForeignKey("RuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("ChildRules") - .HasForeignKey("ParentRuleId") - .OnDelete(DeleteBehavior.NoAction); - - b.HasOne("MicCheck.Api.Segments.Segment", null) - .WithMany("Rules") - .HasForeignKey("SegmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.HasOne("MicCheck.Api.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Navigation("FeatureState"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Navigation("FeatureStateOverrides"); - - b.Navigation("Traits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Navigation("ApiKeys"); - - b.Navigation("Members"); - - b.Navigation("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Navigation("Environments"); - - b.Navigation("Features"); - - b.Navigation("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Navigation("Rules"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Navigation("ChildRules"); - - b.Navigation("Conditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Navigation("Organizations"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260414203426_FixTagRelationships")] + partial class FixTagRelationships + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FeatureTags", b => + { + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("TagsId") + .HasColumnType("integer"); + + b.HasKey("FeatureId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("FeatureTags"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("FeatureTags", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany() + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", null) + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.cs b/src/api/MicCheck.Api/Migrations/20260414203426_FixTagRelationships.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.Designer.cs b/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.Designer.cs old mode 100644 new mode 100755 index 9428e5b..b7d4c48 --- a/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.Designer.cs +++ b/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.Designer.cs @@ -1,928 +1,928 @@ -// -using System; -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace MicCheck.Api.Migrations -{ - [DbContext(typeof(MicCheckDbContext))] - [Migration("20260416184635_AddOrganizationUserNavigation")] - partial class AddOrganizationUserNavigation - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("FeatureTags", b => - { - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("TagsId") - .HasColumnType("integer"); - - b.HasKey("FeatureId", "TagsId"); - - b.HasIndex("TagsId"); - - b.ToTable("FeatureTags"); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Prefix") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.HasKey("Id"); - - b.HasIndex("Key") - .IsUnique(); - - b.HasIndex("OrganizationId"); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ActorUserId") - .HasColumnType("integer"); - - b.Property("Changes") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ResourceType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId", "CreatedAt"); - - b.ToTable("AuditLogs"); - }); - - modelBuilder.Entity("MicCheck.Api.Authorization.UserProjectPermission", b => - { - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("IsAdmin") - .HasColumnType("boolean"); - - b.Property("Permissions") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("UserId", "ProjectId"); - - b.ToTable("UserProjectPermissions"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiKey") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ApiKey") - .IsUnique(); - - b.HasIndex("ProjectId"); - - b.ToTable("Environments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DefaultEnabled") - .HasColumnType("boolean"); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("InitialValue") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("character varying(150)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId", "Name") - .IsUnique(); - - b.ToTable("Features"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("Priority") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("FeatureSegments"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("FeatureId") - .HasColumnType("integer"); - - b.Property("FeatureSegmentId") - .HasColumnType("integer"); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Value") - .HasMaxLength(20000) - .HasColumnType("character varying(20000)"); - - b.Property("Version") - .IsConcurrencyToken() - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.HasIndex("FeatureSegmentId") - .IsUnique(); - - b.HasIndex("IdentityId"); - - b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") - .IsUnique(); - - b.ToTable("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Color") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("Identifier") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId", "Identifier") - .IsUnique(); - - b.ToTable("Identities"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityId") - .HasColumnType("integer"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("ValueType") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("IdentityId", "Key") - .IsUnique(); - - b.ToTable("IdentityTraits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.HasKey("Id"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("integer"); - - b.HasKey("OrganizationId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("OrganizationUsers"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HideDisabledFlags") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("OrganizationId"); - - b.ToTable("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ProjectId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Operator") - .HasColumnType("integer"); - - b.Property("Property") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("RuleId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.HasKey("Id"); - - b.HasIndex("RuleId"); - - b.ToTable("SegmentConditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ParentRuleId") - .HasColumnType("integer"); - - b.Property("SegmentId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("ParentRuleId"); - - b.HasIndex("SegmentId"); - - b.ToTable("SegmentRules"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("Token") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("UserId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("IsTwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("LastLoginAt") - .HasColumnType("timestamp with time zone"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique(); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("EnvironmentId") - .HasColumnType("integer"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("integer"); - - b.Property("Secret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.HasKey("Id"); - - b.HasIndex("EnvironmentId"); - - b.ToTable("Webhooks"); - }); - - modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AttemptNumber") - .HasColumnType("integer"); - - b.Property("AttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Duration") - .HasColumnType("interval"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PayloadJson") - .IsRequired() - .HasColumnType("text"); - - b.Property("ResponseBody") - .HasColumnType("text"); - - b.Property("ResponseStatusCode") - .HasColumnType("integer"); - - b.Property("Success") - .HasColumnType("boolean"); - - b.Property("WebhookId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("WebhookId"); - - b.ToTable("WebhookDeliveryLogs"); - }); - - modelBuilder.Entity("FeatureTags", b => - { - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany() - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Tag", null) - .WithMany() - .HasForeignKey("TagsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("ApiKeys") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Environments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Features") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => - { - b.HasOne("MicCheck.Api.Environments.Environment", null) - .WithMany("FeatureStates") - .HasForeignKey("EnvironmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.Feature", null) - .WithMany("FeatureStates") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Features.FeatureSegment", null) - .WithOne("FeatureState") - .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("FeatureStateOverrides") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Tag", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => - { - b.HasOne("MicCheck.Api.Identities.Identity", null) - .WithMany("Traits") - .HasForeignKey("IdentityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Members") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("MicCheck.Api.Users.User", "User") - .WithMany("Organizations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.HasOne("MicCheck.Api.Organizations.Organization", null) - .WithMany("Projects") - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.HasOne("MicCheck.Api.Projects.Project", null) - .WithMany("Segments") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("Conditions") - .HasForeignKey("RuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.HasOne("MicCheck.Api.Segments.SegmentRule", null) - .WithMany("ChildRules") - .HasForeignKey("ParentRuleId") - .OnDelete(DeleteBehavior.NoAction); - - b.HasOne("MicCheck.Api.Segments.Segment", null) - .WithMany("Rules") - .HasForeignKey("SegmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => - { - b.HasOne("MicCheck.Api.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.Feature", b => - { - b.Navigation("FeatureStates"); - }); - - modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => - { - b.Navigation("FeatureState"); - }); - - modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => - { - b.Navigation("FeatureStateOverrides"); - - b.Navigation("Traits"); - }); - - modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => - { - b.Navigation("ApiKeys"); - - b.Navigation("Members"); - - b.Navigation("Projects"); - }); - - modelBuilder.Entity("MicCheck.Api.Projects.Project", b => - { - b.Navigation("Environments"); - - b.Navigation("Features"); - - b.Navigation("Segments"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => - { - b.Navigation("Rules"); - }); - - modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => - { - b.Navigation("ChildRules"); - - b.Navigation("Conditions"); - }); - - modelBuilder.Entity("MicCheck.Api.Users.User", b => - { - b.Navigation("Organizations"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260416184635_AddOrganizationUserNavigation")] + partial class AddOrganizationUserNavigation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FeatureTags", b => + { + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("TagsId") + .HasColumnType("integer"); + + b.HasKey("FeatureId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("FeatureTags"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("FeatureTags", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany() + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.cs b/src/api/MicCheck.Api/Migrations/20260416184635_AddOrganizationUserNavigation.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.Designer.cs b/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.Designer.cs new file mode 100755 index 0000000..60778c9 --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.Designer.cs @@ -0,0 +1,936 @@ +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260417015326_AddOrganizationInviteToken")] + partial class AddOrganizationInviteToken + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FeatureTags", b => + { + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("TagsId") + .HasColumnType("integer"); + + b.HasKey("FeatureId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("FeatureTags"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InviteToken") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("InviteToken") + .IsUnique() + .HasFilter("\"InviteToken\" IS NOT NULL"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("FeatureTags", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany() + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.cs b/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.cs new file mode 100755 index 0000000..1199d57 --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260417015326_AddOrganizationInviteToken.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + /// + public partial class AddOrganizationInviteToken : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "InviteToken", + table: "Organizations", + type: "character varying(64)", + maxLength: 64, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Organizations_InviteToken", + table: "Organizations", + column: "InviteToken", + unique: true, + filter: "\"InviteToken\" IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Organizations_InviteToken", + table: "Organizations"); + + migrationBuilder.DropColumn( + name: "InviteToken", + table: "Organizations"); + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.Designer.cs b/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.Designer.cs new file mode 100644 index 0000000..daa7c99 --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.Designer.cs @@ -0,0 +1,941 @@ +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260611164933_AddOrganizationUserIsPrimary")] + partial class AddOrganizationUserIsPrimary + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FeatureTags", b => + { + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("TagsId") + .HasColumnType("integer"); + + b.HasKey("FeatureId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("FeatureTags"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InviteToken") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("InviteToken") + .IsUnique() + .HasFilter("\"InviteToken\" IS NOT NULL"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("IsPrimary") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("FeatureTags", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany() + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.cs b/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.cs new file mode 100644 index 0000000..217bc0f --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260611164933_AddOrganizationUserIsPrimary.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + /// + public partial class AddOrganizationUserIsPrimary : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsPrimary", + table: "OrganizationUsers", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsPrimary", + table: "OrganizationUsers"); + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs new file mode 100644 index 0000000..1632da8 --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs @@ -0,0 +1,979 @@ +// +using System; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + [DbContext(typeof(MicCheckDbContext))] + [Migration("20260617194113_AddFeatureUsageDaily")] + partial class AddFeatureUsageDaily + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FeatureTags", b => + { + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("TagsId") + .HasColumnType("integer"); + + b.HasKey("FeatureId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("FeatureTags"); + }); + + modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActorUserId") + .HasColumnType("integer"); + + b.Property("Changes") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("ResourceId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId", "CreatedAt"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => + { + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId", "ProjectId"); + + b.ToTable("UserProjectPermissions"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApiKey") + .IsUnique(); + + b.HasIndex("ProjectId"); + + b.ToTable("Environments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultEnabled") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("InitialValue") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId", "Name") + .IsUnique(); + + b.ToTable("Features"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("FeatureSegments"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureSegmentId") + .HasColumnType("integer"); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasMaxLength(20000) + .HasColumnType("character varying(20000)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.HasIndex("FeatureSegmentId") + .IsUnique(); + + b.HasIndex("IdentityId"); + + b.HasIndex("FeatureId", "EnvironmentId", "IdentityId") + .IsUnique(); + + b.ToTable("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureUsageDaily", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("bigint"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UsageDate") + .HasColumnType("date"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "UsageDate"); + + b.HasIndex("EnvironmentId", "FeatureId", "UsageDate") + .IsUnique(); + + b.ToTable("FeatureUsageDaily"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Color") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("Identifier") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "Identifier") + .IsUnique(); + + b.ToTable("Identities"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IdentityId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IdentityId", "Key") + .IsUnique(); + + b.ToTable("IdentityTraits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InviteToken") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("InviteToken") + .IsUnique() + .HasFilter("\"InviteToken\" IS NOT NULL"); + + b.ToTable("Organizations"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.Property("IsPrimary") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("Role") + .HasColumnType("integer"); + + b.HasKey("OrganizationId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUsers"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HideDisabledFlags") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProjectId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Operator") + .HasColumnType("integer"); + + b.Property("Property") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RuleId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("RuleId"); + + b.ToTable("SegmentConditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ParentRuleId") + .HasColumnType("integer"); + + b.Property("SegmentId") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentRuleId"); + + b.HasIndex("SegmentId"); + + b.ToTable("SegmentRules"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsRevoked") + .HasColumnType("boolean"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsTwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("Secret") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId"); + + b.ToTable("Webhooks"); + }); + + modelBuilder.Entity("MicCheck.Api.Webhooks.WebhookDeliveryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("interval"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PayloadJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseBody") + .HasColumnType("text"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookDeliveryLogs"); + }); + + modelBuilder.Entity("FeatureTags", b => + { + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany() + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Environments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Features") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureState", b => + { + b.HasOne("MicCheck.Api.Environments.Environment", null) + .WithMany("FeatureStates") + .HasForeignKey("EnvironmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.Feature", null) + .WithMany("FeatureStates") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Features.FeatureSegment", null) + .WithOne("FeatureState") + .HasForeignKey("MicCheck.Api.Features.FeatureState", "FeatureSegmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("FeatureStateOverrides") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.IdentityTrait", b => + { + b.HasOne("MicCheck.Api.Identities.Identity", null) + .WithMany("Traits") + .HasForeignKey("IdentityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.OrganizationUser", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Members") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany("Organizations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.HasOne("MicCheck.Api.Organizations.Organization", null) + .WithMany("Projects") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.HasOne("MicCheck.Api.Projects.Project", null) + .WithMany("Segments") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentCondition", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("Conditions") + .HasForeignKey("RuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.HasOne("MicCheck.Api.Segments.SegmentRule", null) + .WithMany("ChildRules") + .HasForeignKey("ParentRuleId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("MicCheck.Api.Segments.Segment", null) + .WithMany("Rules") + .HasForeignKey("SegmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MicCheck.Api.Users.RefreshToken", b => + { + b.HasOne("MicCheck.Api.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MicCheck.Api.Environments.Environment", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.Feature", b => + { + b.Navigation("FeatureStates"); + }); + + modelBuilder.Entity("MicCheck.Api.Features.FeatureSegment", b => + { + b.Navigation("FeatureState"); + }); + + modelBuilder.Entity("MicCheck.Api.Identities.Identity", b => + { + b.Navigation("FeatureStateOverrides"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("MicCheck.Api.Organizations.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Members"); + + b.Navigation("Projects"); + }); + + modelBuilder.Entity("MicCheck.Api.Projects.Project", b => + { + b.Navigation("Environments"); + + b.Navigation("Features"); + + b.Navigation("Segments"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.Segment", b => + { + b.Navigation("Rules"); + }); + + modelBuilder.Entity("MicCheck.Api.Segments.SegmentRule", b => + { + b.Navigation("ChildRules"); + + b.Navigation("Conditions"); + }); + + modelBuilder.Entity("MicCheck.Api.Users.User", b => + { + b.Navigation("Organizations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.cs b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.cs new file mode 100644 index 0000000..509d5d4 --- /dev/null +++ b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MicCheck.Api.Migrations +{ + /// + public partial class AddFeatureUsageDaily : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "FeatureUsageDaily", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EnvironmentId = table.Column(type: "integer", nullable: false), + FeatureId = table.Column(type: "integer", nullable: false), + FeatureName = table.Column(type: "character varying(150)", maxLength: 150, nullable: false), + UsageDate = table.Column(type: "date", nullable: false), + Count = table.Column(type: "bigint", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FeatureUsageDaily", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_FeatureUsageDaily_EnvironmentId_FeatureId_UsageDate", + table: "FeatureUsageDaily", + columns: new[] { "EnvironmentId", "FeatureId", "UsageDate" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_FeatureUsageDaily_EnvironmentId_UsageDate", + table: "FeatureUsageDaily", + columns: new[] { "EnvironmentId", "UsageDate" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FeatureUsageDaily"); + } + } +} diff --git a/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs b/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs old mode 100644 new mode 100755 index 0a5c3c4..f1e18f0 --- a/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs +++ b/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs @@ -37,51 +37,6 @@ namespace MicCheck.Api.Migrations b.ToTable("FeatureTags"); }); - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("OrganizationId") - .HasColumnType("integer"); - - b.Property("Prefix") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.HasKey("Id"); - - b.HasIndex("Key") - .IsUnique(); - - b.HasIndex("OrganizationId"); - - b.ToTable("ApiKeys"); - }); - modelBuilder.Entity("MicCheck.Api.Audit.AuditLog", b => { b.Property("Id") @@ -130,7 +85,52 @@ namespace MicCheck.Api.Migrations b.ToTable("AuditLogs"); }); - modelBuilder.Entity("MicCheck.Api.Authorization.UserProjectPermission", b => + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrganizationId") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.HasIndex("OrganizationId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("MicCheck.Api.Common.Security.Authorization.UserProjectPermission", b => { b.Property("UserId") .HasColumnType("integer"); @@ -302,6 +302,44 @@ namespace MicCheck.Api.Migrations b.ToTable("FeatureStates"); }); + modelBuilder.Entity("MicCheck.Api.Features.FeatureUsageDaily", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("bigint"); + + b.Property("EnvironmentId") + .HasColumnType("integer"); + + b.Property("FeatureId") + .HasColumnType("integer"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UsageDate") + .HasColumnType("date"); + + b.HasKey("Id"); + + b.HasIndex("EnvironmentId", "UsageDate"); + + b.HasIndex("EnvironmentId", "FeatureId", "UsageDate") + .IsUnique(); + + b.ToTable("FeatureUsageDaily"); + }); + modelBuilder.Entity("MicCheck.Api.Features.Tag", b => { b.Property("Id") @@ -400,6 +438,10 @@ namespace MicCheck.Api.Migrations b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); + b.Property("InviteToken") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + b.Property("Name") .IsRequired() .HasMaxLength(200) @@ -407,6 +449,10 @@ namespace MicCheck.Api.Migrations b.HasKey("Id"); + b.HasIndex("InviteToken") + .IsUnique() + .HasFilter("\"InviteToken\" IS NOT NULL"); + b.ToTable("Organizations"); }); @@ -418,6 +464,11 @@ namespace MicCheck.Api.Migrations b.Property("UserId") .HasColumnType("integer"); + b.Property("IsPrimary") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + b.Property("Role") .HasColumnType("integer"); @@ -724,7 +775,7 @@ namespace MicCheck.Api.Migrations .IsRequired(); }); - modelBuilder.Entity("MicCheck.Api.ApiKeys.ApiKey", b => + modelBuilder.Entity("MicCheck.Api.Common.Security.ApiKeys.ApiKey", b => { b.HasOne("MicCheck.Api.Organizations.Organization", null) .WithMany("ApiKeys") diff --git a/src/api/MicCheck.Api/Organizations/.gitkeep b/src/api/MicCheck.Api/Organizations/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/api/MicCheck.Api/Organizations/CreateOrganizationRequest.cs b/src/api/MicCheck.Api/Organizations/CreateOrganizationRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Organizations/InviteTokenResponse.cs b/src/api/MicCheck.Api/Organizations/InviteTokenResponse.cs new file mode 100755 index 0000000..bb54060 --- /dev/null +++ b/src/api/MicCheck.Api/Organizations/InviteTokenResponse.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Organizations; + +public record InviteTokenResponse(string Token); diff --git a/src/api/MicCheck.Api/Organizations/InviteUserRequest.cs b/src/api/MicCheck.Api/Organizations/InviteUserRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Organizations/InviteUsersByEmailRequest.cs b/src/api/MicCheck.Api/Organizations/InviteUsersByEmailRequest.cs new file mode 100755 index 0000000..7b35140 --- /dev/null +++ b/src/api/MicCheck.Api/Organizations/InviteUsersByEmailRequest.cs @@ -0,0 +1,7 @@ +namespace MicCheck.Api.Organizations; + +public record InviteUsersByEmailRequest(IReadOnlyList Invites); + +public record InviteByEmailEntry(string Email, string Role); + +public record InviteByEmailResult(string Email, bool Success, string? Error); diff --git a/src/api/MicCheck.Api/Organizations/Organization.cs b/src/api/MicCheck.Api/Organizations/Organization.cs old mode 100644 new mode 100755 index cb9be19..27bf04e --- a/src/api/MicCheck.Api/Organizations/Organization.cs +++ b/src/api/MicCheck.Api/Organizations/Organization.cs @@ -1,14 +1,15 @@ -using MicCheck.Api.ApiKeys; -using MicCheck.Api.Projects; - -namespace MicCheck.Api.Organizations; - -public class Organization -{ - public int Id { get; init; } - public required string Name { get; set; } - public DateTimeOffset CreatedAt { get; init; } - public ICollection Projects { get; init; } = []; - public ICollection Members { get; init; } = []; - public ICollection ApiKeys { get; init; } = []; -} +using MicCheck.Api.Common.Security.ApiKeys; +using MicCheck.Api.Projects; + +namespace MicCheck.Api.Organizations; + +public class Organization +{ + public int Id { get; init; } + public required string Name { get; set; } + public DateTimeOffset CreatedAt { get; init; } + public ICollection Projects { get; init; } = []; + public ICollection Members { get; init; } = []; + public ICollection ApiKeys { get; init; } = []; + public string? InviteToken { get; set; } +} diff --git a/src/api/MicCheck.Api/Organizations/OrganizationResponse.cs b/src/api/MicCheck.Api/Organizations/OrganizationResponse.cs old mode 100644 new mode 100755 index 3afdecd..81ba7ec --- a/src/api/MicCheck.Api/Organizations/OrganizationResponse.cs +++ b/src/api/MicCheck.Api/Organizations/OrganizationResponse.cs @@ -3,11 +3,12 @@ namespace MicCheck.Api.Organizations; public record OrganizationResponse( int Id, string Name, - DateTimeOffset CreatedAt + DateTimeOffset CreatedAt, + bool IsPrimary ) { - public static OrganizationResponse From(Organization org) => new( - org.Id, org.Name, org.CreatedAt); + public static OrganizationResponse From(Organization org, bool isPrimary = false) => new( + org.Id, org.Name, org.CreatedAt, isPrimary); } public record OrganizationMemberResponse( diff --git a/src/api/MicCheck.Api/Organizations/OrganizationService.cs b/src/api/MicCheck.Api/Organizations/OrganizationService.cs old mode 100644 new mode 100755 index 644786d..1419762 --- a/src/api/MicCheck.Api/Organizations/OrganizationService.cs +++ b/src/api/MicCheck.Api/Organizations/OrganizationService.cs @@ -6,11 +6,16 @@ namespace MicCheck.Api.Organizations; public class OrganizationService(MicCheckDbContext db, AuditService auditService) { - public async Task> ListForUserAsync(int userId, CancellationToken ct = default) + public async Task> ListForUserAsync(int userId, CancellationToken ct = default) { - return await db.Organizations - .Where(o => o.Members.Any(m => m.UserId == userId)) - .ToListAsync(ct); + var rows = await ( + from org in db.Organizations + join member in db.OrganizationUsers on org.Id equals member.OrganizationId + where member.UserId == userId + select new { org, member.IsPrimary } + ).ToListAsync(ct); + + return rows.Select(r => (r.org, r.IsPrimary)).ToList(); } public async Task FindByIdAsync(int id, CancellationToken ct = default) @@ -20,6 +25,8 @@ public class OrganizationService(MicCheckDbContext db, AuditService auditService public async Task CreateAsync(string name, int creatorUserId, CancellationToken ct = default) { + var hasExistingOrg = await db.OrganizationUsers.AnyAsync(ou => ou.UserId == creatorUserId, ct); + var org = new Organization { Name = name, @@ -28,7 +35,8 @@ public class OrganizationService(MicCheckDbContext db, AuditService auditService org.Members.Add(new OrganizationUser { UserId = creatorUserId, - Role = OrganizationRole.Admin + Role = OrganizationRole.Admin, + IsPrimary = !hasExistingOrg }); db.Organizations.Add(org); await db.SaveChangesAsync(ct); @@ -38,6 +46,20 @@ public class OrganizationService(MicCheckDbContext db, AuditService auditService return org; } + public async Task SetPrimaryAsync(int organizationId, int userId, CancellationToken ct = default) + { + var member = await db.OrganizationUsers + .FirstOrDefaultAsync(ou => ou.OrganizationId == organizationId && ou.UserId == userId, ct) + ?? throw new KeyNotFoundException($"User is not a member of organization {organizationId}."); + + await db.OrganizationUsers + .Where(ou => ou.UserId == userId && ou.IsPrimary) + .ExecuteUpdateAsync(s => s.SetProperty(ou => ou.IsPrimary, false), ct); + + member.IsPrimary = true; + await db.SaveChangesAsync(ct); + } + public async Task UpdateAsync(int id, string name, CancellationToken ct = default) { var org = await db.Organizations.FirstOrDefaultAsync(o => o.Id == id, ct) @@ -100,4 +122,67 @@ public class OrganizationService(MicCheckDbContext db, AuditService auditService db.OrganizationUsers.Remove(member); await db.SaveChangesAsync(ct); } + + public async Task GetOrCreateInviteTokenAsync(int organizationId, CancellationToken ct = default) + { + var org = await db.Organizations.FirstOrDefaultAsync(o => o.Id == organizationId, ct) + ?? throw new KeyNotFoundException($"Organization {organizationId} not found."); + + if (org.InviteToken is null) + { + org.InviteToken = Guid.NewGuid().ToString("N"); + await db.SaveChangesAsync(ct); + } + + return org.InviteToken; + } + + public async Task RegenerateInviteTokenAsync(int organizationId, CancellationToken ct = default) + { + var org = await db.Organizations.FirstOrDefaultAsync(o => o.Id == organizationId, ct) + ?? throw new KeyNotFoundException($"Organization {organizationId} not found."); + + org.InviteToken = Guid.NewGuid().ToString("N"); + await db.SaveChangesAsync(ct); + return org.InviteToken; + } + + public async Task FindByInviteTokenAsync(string token, CancellationToken ct = default) => + await db.Organizations.FirstOrDefaultAsync(o => o.InviteToken == token, ct); + + public async Task> InviteUsersByEmailAsync(int organizationId, IReadOnlyList invites, CancellationToken ct = default) + { + var results = new List(); + + foreach (var invite in invites) + { + var user = await db.Users + .FirstOrDefaultAsync(u => u.Email == invite.Email.Trim().ToLower() && u.IsActive, ct); + + if (user is null) + { + results.Add(new InviteByEmailResult(invite.Email, false, "No user found with that email address.")); + continue; + } + + if (!Enum.TryParse(invite.Role, ignoreCase: true, out var role)) + { + results.Add(new InviteByEmailResult(invite.Email, false, $"Invalid role '{invite.Role}'.")); + continue; + } + + await InviteUserAsync(organizationId, user.Id, role, ct); + results.Add(new InviteByEmailResult(invite.Email, true, null)); + } + + return results; + } + + public async Task AcceptInviteAsync(string token, int userId, CancellationToken ct = default) + { + var org = await FindByInviteTokenAsync(token, ct) + ?? throw new KeyNotFoundException("Invalid or expired invite link."); + + await InviteUserAsync(org.Id, userId, OrganizationRole.User, ct); + } } diff --git a/src/api/MicCheck.Api/Organizations/OrganizationUser.cs b/src/api/MicCheck.Api/Organizations/OrganizationUser.cs old mode 100644 new mode 100755 index 2c7ebbb..f12b701 --- a/src/api/MicCheck.Api/Organizations/OrganizationUser.cs +++ b/src/api/MicCheck.Api/Organizations/OrganizationUser.cs @@ -7,6 +7,7 @@ public class OrganizationUser public int OrganizationId { get; init; } public int UserId { get; init; } public OrganizationRole Role { get; set; } + public bool IsPrimary { get; set; } public User User { get; init; } = null!; } diff --git a/src/api/MicCheck.Api/Organizations/OrganizationsController.cs b/src/api/MicCheck.Api/Organizations/OrganizationsController.cs old mode 100644 new mode 100755 index fbe9776..6ae1c3c --- a/src/api/MicCheck.Api/Organizations/OrganizationsController.cs +++ b/src/api/MicCheck.Api/Organizations/OrganizationsController.cs @@ -1,155 +1,220 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using MicCheck.Api.Webhooks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Organizations; - -[ApiController] -[Route("api/v1/organisations")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class OrganizationsController(OrganizationService organizationService, WebhookService webhookService) : ControllerBase -{ - [HttpGet] - public async Task>> List( - [FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var userId = GetCurrentUserId(); - if (userId is null) return Unauthorized(); - - var all = await organizationService.ListForUserAsync(userId.Value, ct); - var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(OrganizationResponse.From).ToList(); - - return Ok(new PaginatedResponse(all.Count, null, null, paged)); - } - - [HttpPost] - public async Task> Create( - CreateOrganizationRequest request, CancellationToken ct) - { - var userId = GetCurrentUserId(); - if (userId is null) return Unauthorized(); - - var org = await organizationService.CreateAsync(request.Name, userId.Value, ct); - return CreatedAtAction(nameof(GetById), new { id = org.Id }, OrganizationResponse.From(org)); - } - - [HttpGet("{id}")] - public async Task> GetById(int id, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - return Ok(OrganizationResponse.From(org)); - } - - [HttpPut("{id}")] - public async Task> Update( - int id, UpdateOrganizationRequest request, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var updated = await organizationService.UpdateAsync(id, request.Name, ct); - return Ok(OrganizationResponse.From(updated)); - } - - [HttpDelete("{id}")] - public async Task Delete(int id, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - await organizationService.DeleteAsync(id, ct); - return NoContent(); - } - - [HttpGet("{id}/users")] - public async Task>> ListUsers( - int id, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var members = await organizationService.ListMembersAsync(id, ct); - return Ok(members.Select(OrganizationMemberResponse.From).ToList()); - } - - [HttpPost("{id}/users/invite")] - public async Task InviteUser(int id, InviteUserRequest request, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var role = Enum.Parse(request.Role, ignoreCase: true); - await organizationService.InviteUserAsync(id, request.UserId, role, ct); - return Ok(); - } - - [HttpDelete("{id}/users/{userId}")] - public async Task RemoveUser(int id, int userId, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - await organizationService.RemoveMemberAsync(id, userId, ct); - return NoContent(); - } - - [HttpGet("{id}/webhooks")] - public async Task>> ListWebhooks(int id, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var webhooks = await webhookService.ListByOrganizationAsync(id, ct); - return Ok(webhooks.Select(WebhookResponse.From).ToList()); - } - - [HttpPost("{id}/webhooks")] - public async Task> CreateWebhook( - int id, CreateWebhookRequest request, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var webhook = await webhookService.CreateForOrganizationAsync(id, request.Url, request.Secret, request.Enabled, ct); - return CreatedAtAction(nameof(ListWebhooks), new { id }, WebhookResponse.From(webhook)); - } - - [HttpPut("{id}/webhooks/{webhookId}")] - public async Task> UpdateWebhook( - int id, int webhookId, CreateWebhookRequest request, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var webhook = await webhookService.FindByIdAsync(webhookId, ct); - if (webhook is null || webhook.OrganizationId != id) return NotFound(); - - var updated = await webhookService.UpdateAsync(webhookId, request.Url, request.Secret, request.Enabled, ct); - return Ok(WebhookResponse.From(updated)); - } - - [HttpDelete("{id}/webhooks/{webhookId}")] - public async Task DeleteWebhook(int id, int webhookId, CancellationToken ct) - { - var org = await organizationService.FindByIdAsync(id, ct); - if (org is null) return NotFound(); - - var webhook = await webhookService.FindByIdAsync(webhookId, ct); - if (webhook is null || webhook.OrganizationId != id) return NotFound(); - - await webhookService.DeleteAsync(webhookId, ct); - return NoContent(); - } - - private int? GetCurrentUserId() - { - var claim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; - return int.TryParse(claim, out var id) ? id : null; - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using MicCheck.Api.Webhooks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Organizations; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class OrganizationsController(OrganizationService organizationService, WebhookService webhookService) : ControllerBase +{ + [HttpGet("api/v1/organisations")] + public async Task>> List( + [FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + var all = await organizationService.ListForUserAsync(userId.Value, ct); + var paged = all.Skip((page - 1) * pageSize).Take(pageSize) + .Select(x => OrganizationResponse.From(x.Org, x.IsPrimary)).ToList(); + + return Ok(new PaginatedResponse(all.Count, null, null, paged)); + } + + [HttpPost("api/v1/organisations")] + public async Task> Create( + CreateOrganizationRequest request, CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + var org = await organizationService.CreateAsync(request.Name, userId.Value, ct); + return CreatedAtAction(nameof(GetById), new { id = org.Id }, OrganizationResponse.From(org)); + } + + [HttpGet("api/v1/organisation/{id}")] + public async Task> GetById(int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + return Ok(OrganizationResponse.From(org)); + } + + [HttpPut("api/v1/organisation/{id}")] + public async Task> Update( + int id, UpdateOrganizationRequest request, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var updated = await organizationService.UpdateAsync(id, request.Name, ct); + return Ok(OrganizationResponse.From(updated)); + } + + [HttpPut("api/v1/organisation/{id}/primary")] + public async Task SetPrimary(int id, CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + try + { + await organizationService.SetPrimaryAsync(id, userId.Value, ct); + return NoContent(); + } + catch (KeyNotFoundException) + { + return NotFound(); + } + } + + [HttpDelete("api/v1/organisation/{id}")] + public async Task Delete(int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + await organizationService.DeleteAsync(id, ct); + return NoContent(); + } + + [HttpGet("api/v1/organisation/{id}/users")] + public async Task>> ListUsers( + int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var members = await organizationService.ListMembersAsync(id, ct); + return Ok(members.Select(OrganizationMemberResponse.From).ToList()); + } + + [HttpPost("api/v1/organisation/{id}/users/invite")] + public async Task InviteUser(int id, InviteUserRequest request, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var role = Enum.Parse(request.Role, ignoreCase: true); + await organizationService.InviteUserAsync(id, request.UserId, role, ct); + return Ok(); + } + + [HttpPost("api/v1/organisation/{id}/users/invite-by-email")] + public async Task>> InviteUsersByEmail( + int id, InviteUsersByEmailRequest request, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var results = await organizationService.InviteUsersByEmailAsync(id, request.Invites, ct); + return Ok(results); + } + + [HttpGet("api/v1/organisation/{id}/invite-link")] + public async Task> GetInviteLink(int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var token = await organizationService.GetOrCreateInviteTokenAsync(id, ct); + return Ok(new InviteTokenResponse(token)); + } + + [HttpPost("api/v1/organisation/{id}/invite-link/regenerate")] + public async Task> RegenerateInviteLink(int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var token = await organizationService.RegenerateInviteTokenAsync(id, ct); + return Ok(new InviteTokenResponse(token)); + } + + [HttpPost("api/v1/organisations/invite/{token}/accept")] + public async Task AcceptInvite(string token, CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + try + { + await organizationService.AcceptInviteAsync(token, userId.Value, ct); + return Ok(); + } + catch (KeyNotFoundException) + { + return NotFound("Invalid or expired invite link."); + } + } + + [HttpDelete("api/v1/organisation/{id}/user/{userId}")] + public async Task RemoveUser(int id, int userId, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + await organizationService.RemoveMemberAsync(id, userId, ct); + return NoContent(); + } + + [HttpGet("api/v1/organisation/{id}/webhooks")] + public async Task>> ListWebhooks(int id, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var webhooks = await webhookService.ListByOrganizationAsync(id, ct); + return Ok(webhooks.Select(WebhookResponse.From).ToList()); + } + + [HttpPost("api/v1/organisation/{id}/webhooks")] + public async Task> CreateWebhook( + int id, CreateWebhookRequest request, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var webhook = await webhookService.CreateForOrganizationAsync(id, request.Url, request.Secret, request.Enabled, ct); + return CreatedAtAction(nameof(ListWebhooks), new { id }, WebhookResponse.From(webhook)); + } + + [HttpPut("api/v1/organisation/{id}/webhook/{webhookId}")] + public async Task> UpdateWebhook( + int id, int webhookId, CreateWebhookRequest request, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var webhook = await webhookService.FindByIdAsync(webhookId, ct); + if (webhook is null || webhook.OrganizationId != id) return NotFound(); + + var updated = await webhookService.UpdateAsync(webhookId, request.Url, request.Secret, request.Enabled, ct); + return Ok(WebhookResponse.From(updated)); + } + + [HttpDelete("api/v1/organisation/{id}/webhook/{webhookId}")] + public async Task DeleteWebhook(int id, int webhookId, CancellationToken ct) + { + var org = await organizationService.FindByIdAsync(id, ct); + if (org is null) return NotFound(); + + var webhook = await webhookService.FindByIdAsync(webhookId, ct); + if (webhook is null || webhook.OrganizationId != id) return NotFound(); + + await webhookService.DeleteAsync(webhookId, ct); + return NoContent(); + } + + private int? GetCurrentUserId() + { + var claim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; + return int.TryParse(claim, out var id) ? id : null; + } +} diff --git a/src/api/MicCheck.Api/Organizations/UpdateOrganizationRequest.cs b/src/api/MicCheck.Api/Organizations/UpdateOrganizationRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Program.cs b/src/api/MicCheck.Api/Program.cs old mode 100644 new mode 100755 index 0d97d7f..61dcde7 --- a/src/api/MicCheck.Api/Program.cs +++ b/src/api/MicCheck.Api/Program.cs @@ -1,186 +1,188 @@ -using System.Text; -using System.Threading.RateLimiting; -using FluentValidation; -using FluentValidation.AspNetCore; -using MicCheck.Api.ApiKeys; -using MicCheck.Api.Audit; -using MicCheck.Api.Authentication; -using MicCheck.Api.Authorization; -using MicCheck.Api.Data; -using MicCheck.Api.Environments; -using MicCheck.Api.Features; -using MicCheck.Api.Identities; -using MicCheck.Api.Organizations; -using MicCheck.Api.Projects; -using MicCheck.Api.Segments; -using MicCheck.Api.Users; -using MicCheck.Api.Webhooks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Scalar.AspNetCore; -using Serilog; - -Log.Logger = new LoggerConfiguration() - .WriteTo.Console() - .CreateBootstrapLogger(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - builder.Host.UseSerilog((context, services, config) => - config.ReadFrom.Configuration(context.Configuration) - .ReadFrom.Services(services) - .WriteTo.Console()); - - builder.Services.AddOpenApi(); - builder.Services.AddControllers() - .AddJsonOptions(options => - options.JsonSerializerOptions.Converters.Add( - new System.Text.Json.Serialization.JsonStringEnumConverter())); - - builder.Services.AddAuthentication() - .AddScheme( - EnvironmentKeyAuthenticationHandler.SchemeName, _ => { }) - .AddScheme( - ApiKeyAuthenticationHandler.SchemeName, _ => { }) - .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidateAudience = true, - ValidateIssuerSigningKey = true, - ValidIssuer = builder.Configuration["Jwt:Issuer"], - ValidAudience = builder.Configuration["Jwt:Audience"], - IssuerSigningKey = new SymmetricSecurityKey( - Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]!)) - }; - }); - - builder.Services.AddAuthorization(options => - { - options.AddPolicy(AuthorizationPolicies.FlagsApiAccess, policy => - policy.AddAuthenticationSchemes(EnvironmentKeyAuthenticationHandler.SchemeName) - .RequireClaim("EnvironmentId")); - - options.AddPolicy(AuthorizationPolicies.AdminApiAccess, policy => - policy.AddAuthenticationSchemes(ApiKeyAuthenticationHandler.SchemeName, JwtBearerDefaults.AuthenticationScheme) - .RequireAuthenticatedUser()); - - options.AddPolicy(AuthorizationPolicies.OrganizationAdmin, policy => - policy.AddAuthenticationSchemes(ApiKeyAuthenticationHandler.SchemeName, JwtBearerDefaults.AuthenticationScheme) - .RequireClaim("OrganizationRole", "Admin")); - }); - - builder.Services.AddHttpContextAccessor(); - - builder.Services.AddRateLimiter(options => - options.AddFixedWindowLimiter("AdminApi", limiter => - { - limiter.PermitLimit = 500; - limiter.Window = TimeSpan.FromMinutes(1); - limiter.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; - limiter.QueueLimit = 0; - })); - - builder.Services.AddFluentValidationAutoValidation(); - builder.Services.AddValidatorsFromAssemblyContaining(); - - builder.Services.Configure(options => - { - options.InvalidModelStateResponseFactory = context => - { - var errors = context.ModelState - .Where(e => e.Value?.Errors.Count > 0) - .ToDictionary( - kvp => kvp.Key, - kvp => kvp.Value!.Errors.Select(e => e.ErrorMessage).ToArray()); - return new UnprocessableEntityObjectResult(new { errors }); - }; - }); - - builder.Services.AddMemoryCache(); - - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped, PasswordHasher>(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddSingleton(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHttpClient("Webhooks", client => - client.DefaultRequestHeaders.Add("User-Agent", "MicCheck-Webhook/1.0")); - - var connectionString = System.Environment.GetEnvironmentVariable("DATABASE_URL") is { } databaseUrl - ? DatabaseUrlParser.ToNpgsqlConnectionString(databaseUrl) - : builder.Configuration.GetConnectionString("DefaultConnection")!; - - builder.Services.AddDbContext(options => - options.UseNpgsql(connectionString)); - - var app = builder.Build(); - - // Apply any pending EF Core migrations on startup (safe to run on every boot) - using (var migrationScope = app.Services.CreateScope()) - { - var db = migrationScope.ServiceProvider.GetRequiredService(); - await db.Database.MigrateAsync(); - } - - if (app.Environment.IsDevelopment()) - { - app.MapOpenApi(); - app.MapScalarApiReference(); - app.MapGet("/", () => Results.Redirect("/scalar/v1")).ExcludeFromDescription(); - - using var scope = app.Services.CreateScope(); - var seeder = scope.ServiceProvider.GetRequiredService(); - await seeder.SeedAsync(); - } - - app.UseSerilogRequestLogging(); - app.UseRateLimiter(); - app.UseAuthentication(); - app.UseAuthorization(); - - app.MapControllers(); - app.MapAuthEndpoints(); - app.MapApiKeyEndpoints(); - - app.Run(); -} -catch (Exception ex) -{ - Log.Fatal(ex, "Application terminated unexpectedly"); -} -finally -{ - Log.CloseAndFlush(); -} +using System.Text; +using System.Threading.RateLimiting; +using FluentValidation; +using FluentValidation.AspNetCore; +using MicCheck.Api.Common.Security.ApiKeys; +using MicCheck.Api.Audit; +using MicCheck.Api.Common.Security.Authentication; +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Data; +using MicCheck.Api.Environments; +using MicCheck.Api.Features; +using MicCheck.Api.Identities; +using MicCheck.Api.Organizations; +using MicCheck.Api.Projects; +using MicCheck.Api.Segments; +using MicCheck.Api.Users; +using MicCheck.Api.Webhooks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Scalar.AspNetCore; +using Serilog; + +Log.Logger = new LoggerConfiguration() + .WriteTo.Console() + .CreateBootstrapLogger(); + +try +{ + var builder = WebApplication.CreateBuilder(args); + + builder.AddServiceDefaults(); + + builder.Host.UseSerilog((context, services, config) => + config.ReadFrom.Configuration(context.Configuration) + .ReadFrom.Services(services) + .WriteTo.Console()); + + builder.Services.AddOpenApi(); + builder.Services.AddControllers() + .AddJsonOptions(options => + options.JsonSerializerOptions.Converters.Add( + new System.Text.Json.Serialization.JsonStringEnumConverter())); + + builder.Services.AddAuthentication() + .AddScheme( + EnvironmentKeyAuthenticationHandler.SchemeName, _ => { }) + .AddScheme( + ApiKeyAuthenticationHandler.SchemeName, _ => { }) + .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateIssuerSigningKey = true, + ValidIssuer = builder.Configuration["Jwt:Issuer"], + ValidAudience = builder.Configuration["Jwt:Audience"], + IssuerSigningKey = new SymmetricSecurityKey( + Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]!)) + }; + }); + + builder.Services.AddAuthorization(options => + { + options.AddPolicy(AuthorizationPolicies.FlagsApiAccess, policy => + policy.AddAuthenticationSchemes(EnvironmentKeyAuthenticationHandler.SchemeName) + .RequireClaim("EnvironmentId")); + + options.AddPolicy(AuthorizationPolicies.AdminApiAccess, policy => + policy.AddAuthenticationSchemes(ApiKeyAuthenticationHandler.SchemeName, JwtBearerDefaults.AuthenticationScheme) + .RequireAuthenticatedUser()); + + options.AddPolicy(AuthorizationPolicies.OrganizationAdmin, policy => + policy.AddAuthenticationSchemes(ApiKeyAuthenticationHandler.SchemeName, JwtBearerDefaults.AuthenticationScheme) + .RequireClaim("OrganizationRole", "Admin")); + }); + + builder.Services.AddHttpContextAccessor(); + + builder.Services.AddRateLimiter(options => + options.AddFixedWindowLimiter("AdminApi", limiter => + { + limiter.PermitLimit = 500; + limiter.Window = TimeSpan.FromMinutes(1); + limiter.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; + limiter.QueueLimit = 0; + })); + + builder.Services.AddFluentValidationAutoValidation(); + builder.Services.AddValidatorsFromAssemblyContaining(); + + builder.Services.Configure(options => + { + options.InvalidModelStateResponseFactory = context => + { + var errors = context.ModelState + .Where(e => e.Value?.Errors.Count > 0) + .ToDictionary( + kvp => kvp.Key, + kvp => kvp.Value!.Errors.Select(e => e.ErrorMessage).ToArray()); + return new UnprocessableEntityObjectResult(new { errors }); + }; + }); + + builder.Services.AddMemoryCache(); + builder.Services.AddMetrics(); + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped, PasswordHasher>(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddSingleton(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddSingleton(); + builder.Services.AddScoped(); + builder.Services.AddHostedService(); + builder.Services.AddHttpClient("Webhooks", client => + client.DefaultRequestHeaders.Add("User-Agent", "MicCheck-Webhook/1.0")); + + var connectionString = builder.Configuration.GetConnectionString("miccheck") + ?? (System.Environment.GetEnvironmentVariable("DATABASE_URL") is { } databaseUrl + ? DatabaseUrlParser.ToNpgsqlConnectionString(databaseUrl) + : builder.Configuration.GetConnectionString("DefaultConnection")!); + + builder.Services.AddDbContext(options => + options.UseNpgsql(connectionString)); + + var app = builder.Build(); + + await app.ApplyMigrationsAsync(); + + if (app.Environment.IsDevelopment()) + { + app.MapOpenApi(); + app.MapScalarApiReference(); + app.MapGet("/", () => Results.Redirect("/scalar/v1")).ExcludeFromDescription(); + + await app.SeedDevelopmentDataAsync(); + } + + app.UseSerilogRequestLogging(); + app.UseRateLimiter(); + app.UseAuthentication(); + app.UseAuthorization(); + + app.MapDefaultEndpoints(); + app.MapControllers(); + app.MapAuthEndpoints(); + app.MapApiKeyEndpoints(); + + app.Run(); +} +catch (Exception ex) +{ + Log.Fatal(ex, "Application terminated unexpectedly"); +} +finally +{ + Log.CloseAndFlush(); +} diff --git a/src/api/MicCheck.Api/Projects/.gitkeep b/src/api/MicCheck.Api/Projects/.gitkeep old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Projects/CreateProjectRequest.cs b/src/api/MicCheck.Api/Projects/CreateProjectRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Projects/Project.cs b/src/api/MicCheck.Api/Projects/Project.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Projects/ProjectResponse.cs b/src/api/MicCheck.Api/Projects/ProjectResponse.cs old mode 100644 new mode 100755 index 7740dee..1fadd4f --- a/src/api/MicCheck.Api/Projects/ProjectResponse.cs +++ b/src/api/MicCheck.Api/Projects/ProjectResponse.cs @@ -1,27 +1,27 @@ -using MicCheck.Api.Authorization; - -namespace MicCheck.Api.Projects; - -public record ProjectResponse( - int Id, - string Name, - int OrganizationId, - bool HideDisabledFlags, - DateTimeOffset CreatedAt -) -{ - public static ProjectResponse From(Project project) => new( - project.Id, project.Name, project.OrganizationId, project.HideDisabledFlags, project.CreatedAt); -} - -public record UserPermissionResponse( - int UserId, - int ProjectId, - bool IsAdmin, - IReadOnlyList Permissions -) -{ - public static UserPermissionResponse From(UserProjectPermission p) => new( - p.UserId, p.ProjectId, p.IsAdmin, - p.Permissions.Select(x => x.ToString()).ToList()); -} +using MicCheck.Api.Common.Security.Authorization; + +namespace MicCheck.Api.Projects; + +public record ProjectResponse( + int Id, + string Name, + int OrganizationId, + bool HideDisabledFlags, + DateTimeOffset CreatedAt +) +{ + public static ProjectResponse From(Project project) => new( + project.Id, project.Name, project.OrganizationId, project.HideDisabledFlags, project.CreatedAt); +} + +public record UserPermissionResponse( + int UserId, + int ProjectId, + bool IsAdmin, + IReadOnlyList Permissions +) +{ + public static UserPermissionResponse From(UserProjectPermission p) => new( + p.UserId, p.ProjectId, p.IsAdmin, + p.Permissions.Select(x => x.ToString()).ToList()); +} diff --git a/src/api/MicCheck.Api/Projects/ProjectService.cs b/src/api/MicCheck.Api/Projects/ProjectService.cs old mode 100644 new mode 100755 index 8ef4df0..66e6251 --- a/src/api/MicCheck.Api/Projects/ProjectService.cs +++ b/src/api/MicCheck.Api/Projects/ProjectService.cs @@ -1,105 +1,105 @@ -using MicCheck.Api.Audit; -using MicCheck.Api.Authorization; -using MicCheck.Api.Data; -using Microsoft.EntityFrameworkCore; - -namespace MicCheck.Api.Projects; - -public class ProjectService(MicCheckDbContext db, AuditService auditService) -{ - public async Task> ListByOrganizationAsync(int organizationId, CancellationToken ct = default) - { - return await db.Projects - .Where(p => p.OrganizationId == organizationId) - .ToListAsync(ct); - } - - public async Task FindByIdAsync(int id, CancellationToken ct = default) - { - return await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct); - } - - public async Task CreateAsync(int organizationId, string name, CancellationToken ct = default) - { - var project = new Project - { - Name = name, - OrganizationId = organizationId, - CreatedAt = DateTimeOffset.UtcNow - }; - db.Projects.Add(project); - await db.SaveChangesAsync(ct); - - await auditService.LogAsync("Project", project.Id.ToString(), "created", organizationId, project.Id, ct: ct); - - return project; - } - - public async Task UpdateAsync(int id, string name, bool hideDisabledFlags, CancellationToken ct = default) - { - var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct) - ?? throw new KeyNotFoundException($"Project {id} not found."); - - project.Name = name; - project.HideDisabledFlags = hideDisabledFlags; - await db.SaveChangesAsync(ct); - - await auditService.LogAsync("Project", project.Id.ToString(), "updated", project.OrganizationId, project.Id, ct: ct); - - return project; - } - - public async Task DeleteAsync(int id, CancellationToken ct = default) - { - var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct); - if (project is null) return; - - db.Projects.Remove(project); - await db.SaveChangesAsync(ct); - } - - public async Task> ListUserPermissionsAsync(int projectId, CancellationToken ct = default) - { - return await db.UserProjectPermissions - .Where(p => p.ProjectId == projectId) - .ToListAsync(ct); - } - - public async Task SetUserPermissionsAsync( - int projectId, int userId, bool isAdmin, List permissions, CancellationToken ct = default) - { - var existing = await db.UserProjectPermissions - .FirstOrDefaultAsync(p => p.ProjectId == projectId && p.UserId == userId, ct); - - if (existing is not null) - { - existing.IsAdmin = isAdmin; - existing.Permissions = permissions; - } - else - { - existing = new UserProjectPermission - { - ProjectId = projectId, - UserId = userId, - IsAdmin = isAdmin, - Permissions = permissions - }; - db.UserProjectPermissions.Add(existing); - } - - await db.SaveChangesAsync(ct); - return existing; - } - - public async Task RemoveUserPermissionsAsync(int projectId, int userId, CancellationToken ct = default) - { - var perm = await db.UserProjectPermissions - .FirstOrDefaultAsync(p => p.ProjectId == projectId && p.UserId == userId, ct); - - if (perm is null) return; - - db.UserProjectPermissions.Remove(perm); - await db.SaveChangesAsync(ct); - } -} +using MicCheck.Api.Audit; +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Data; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Projects; + +public class ProjectService(MicCheckDbContext db, AuditService auditService) +{ + public async Task> ListByOrganizationAsync(int organizationId, CancellationToken ct = default) + { + return await db.Projects + .Where(p => p.OrganizationId == organizationId) + .ToListAsync(ct); + } + + public async Task FindByIdAsync(int id, CancellationToken ct = default) + { + return await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct); + } + + public async Task CreateAsync(int organizationId, string name, CancellationToken ct = default) + { + var project = new Project + { + Name = name, + OrganizationId = organizationId, + CreatedAt = DateTimeOffset.UtcNow + }; + db.Projects.Add(project); + await db.SaveChangesAsync(ct); + + await auditService.LogAsync("Project", project.Id.ToString(), "created", organizationId, project.Id, ct: ct); + + return project; + } + + public async Task UpdateAsync(int id, string name, bool hideDisabledFlags, CancellationToken ct = default) + { + var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct) + ?? throw new KeyNotFoundException($"Project {id} not found."); + + project.Name = name; + project.HideDisabledFlags = hideDisabledFlags; + await db.SaveChangesAsync(ct); + + await auditService.LogAsync("Project", project.Id.ToString(), "updated", project.OrganizationId, project.Id, ct: ct); + + return project; + } + + public async Task DeleteAsync(int id, CancellationToken ct = default) + { + var project = await db.Projects.FirstOrDefaultAsync(p => p.Id == id, ct); + if (project is null) return; + + db.Projects.Remove(project); + await db.SaveChangesAsync(ct); + } + + public async Task> ListUserPermissionsAsync(int projectId, CancellationToken ct = default) + { + return await db.UserProjectPermissions + .Where(p => p.ProjectId == projectId) + .ToListAsync(ct); + } + + public async Task SetUserPermissionsAsync( + int projectId, int userId, bool isAdmin, List permissions, CancellationToken ct = default) + { + var existing = await db.UserProjectPermissions + .FirstOrDefaultAsync(p => p.ProjectId == projectId && p.UserId == userId, ct); + + if (existing is not null) + { + existing.IsAdmin = isAdmin; + existing.Permissions = permissions; + } + else + { + existing = new UserProjectPermission + { + ProjectId = projectId, + UserId = userId, + IsAdmin = isAdmin, + Permissions = permissions + }; + db.UserProjectPermissions.Add(existing); + } + + await db.SaveChangesAsync(ct); + return existing; + } + + public async Task RemoveUserPermissionsAsync(int projectId, int userId, CancellationToken ct = default) + { + var perm = await db.UserProjectPermissions + .FirstOrDefaultAsync(p => p.ProjectId == projectId && p.UserId == userId, ct); + + if (perm is null) return; + + db.UserProjectPermissions.Remove(perm); + await db.SaveChangesAsync(ct); + } +} diff --git a/src/api/MicCheck.Api/Projects/ProjectsController.cs b/src/api/MicCheck.Api/Projects/ProjectsController.cs old mode 100644 new mode 100755 index 3934b2b..1a66d3c --- a/src/api/MicCheck.Api/Projects/ProjectsController.cs +++ b/src/api/MicCheck.Api/Projects/ProjectsController.cs @@ -1,113 +1,112 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Projects; - -[ApiController] -[Route("api/v1/projects")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class ProjectsController(ProjectService projectService) : ControllerBase -{ - [HttpGet] - public async Task>> List( - [FromQuery] int organizationId, - [FromQuery] int page = 1, - [FromQuery] int pageSize = 20, - CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var all = await projectService.ListByOrganizationAsync(organizationId, ct); - var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(ProjectResponse.From).ToList(); - return Ok(new PaginatedResponse(all.Count, null, null, paged)); - } - - [HttpPost] - public async Task> Create(CreateProjectRequest request, CancellationToken ct) - { - var project = await projectService.CreateAsync(request.OrganizationId, request.Name, ct); - return CreatedAtAction(nameof(GetById), new { id = project.Id }, ProjectResponse.From(project)); - } - - [HttpGet("{id}")] - public async Task> GetById(int id, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - return Ok(ProjectResponse.From(project)); - } - - [HttpPut("{id}")] - public async Task> Update(int id, UpdateProjectRequest request, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - var updated = await projectService.UpdateAsync(id, request.Name, request.HideDisabledFlags, ct); - return Ok(ProjectResponse.From(updated)); - } - - [HttpDelete("{id}")] - public async Task Delete(int id, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - await projectService.DeleteAsync(id, ct); - return NoContent(); - } - - [HttpGet("{id}/user-permissions")] - public async Task>> ListUserPermissions( - int id, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - var perms = await projectService.ListUserPermissionsAsync(id, ct); - return Ok(perms.Select(UserPermissionResponse.From).ToList()); - } - - [HttpPost("{id}/user-permissions")] - public async Task> CreateUserPermissions( - int id, SetUserPermissionsRequest request, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - var permissions = request.Permissions - .Select(p => Enum.Parse(p, ignoreCase: true)) - .ToList(); - - var perm = await projectService.SetUserPermissionsAsync(id, request.UserId, request.IsAdmin, permissions, ct); - return Ok(UserPermissionResponse.From(perm)); - } - - [HttpPut("{id}/user-permissions/{userId}")] - public async Task> UpdateUserPermissions( - int id, int userId, SetUserPermissionsRequest request, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - var permissions = request.Permissions - .Select(p => Enum.Parse(p, ignoreCase: true)) - .ToList(); - - var perm = await projectService.SetUserPermissionsAsync(id, userId, request.IsAdmin, permissions, ct); - return Ok(UserPermissionResponse.From(perm)); - } - - [HttpDelete("{id}/user-permissions/{userId}")] - public async Task DeleteUserPermissions(int id, int userId, CancellationToken ct) - { - var project = await projectService.FindByIdAsync(id, ct); - if (project is null) return NotFound(); - - await projectService.RemoveUserPermissionsAsync(id, userId, ct); - return NoContent(); - } -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Projects; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class ProjectsController(ProjectService projectService) : ControllerBase +{ + [HttpGet("api/v1/projects")] + public async Task>> List( + [FromQuery] int organizationId, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20, + CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var all = await projectService.ListByOrganizationAsync(organizationId, ct); + var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(ProjectResponse.From).ToList(); + return Ok(new PaginatedResponse(all.Count, null, null, paged)); + } + + [HttpPost("api/v1/projects")] + public async Task> Create(CreateProjectRequest request, CancellationToken ct) + { + var project = await projectService.CreateAsync(request.OrganizationId, request.Name, ct); + return CreatedAtAction(nameof(GetById), new { id = project.Id }, ProjectResponse.From(project)); + } + + [HttpGet("api/v1/project/{id}")] + public async Task> GetById(int id, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + return Ok(ProjectResponse.From(project)); + } + + [HttpPut("api/v1/project/{id}")] + public async Task> Update(int id, UpdateProjectRequest request, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + var updated = await projectService.UpdateAsync(id, request.Name, request.HideDisabledFlags, ct); + return Ok(ProjectResponse.From(updated)); + } + + [HttpDelete("api/v1/project/{id}")] + public async Task Delete(int id, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + await projectService.DeleteAsync(id, ct); + return NoContent(); + } + + [HttpGet("api/v1/project/{id}/user-permissions")] + public async Task>> ListUserPermissions( + int id, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + var perms = await projectService.ListUserPermissionsAsync(id, ct); + return Ok(perms.Select(UserPermissionResponse.From).ToList()); + } + + [HttpPost("api/v1/project/{id}/user-permissions")] + public async Task> CreateUserPermissions( + int id, SetUserPermissionsRequest request, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + var permissions = request.Permissions + .Select(p => Enum.Parse(p, ignoreCase: true)) + .ToList(); + + var perm = await projectService.SetUserPermissionsAsync(id, request.UserId, request.IsAdmin, permissions, ct); + return Ok(UserPermissionResponse.From(perm)); + } + + [HttpPut("api/v1/project/{id}/user-permission/{userId}")] + public async Task> UpdateUserPermissions( + int id, int userId, SetUserPermissionsRequest request, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + var permissions = request.Permissions + .Select(p => Enum.Parse(p, ignoreCase: true)) + .ToList(); + + var perm = await projectService.SetUserPermissionsAsync(id, userId, request.IsAdmin, permissions, ct); + return Ok(UserPermissionResponse.From(perm)); + } + + [HttpDelete("api/v1/project/{id}/user-permission/{userId}")] + public async Task DeleteUserPermissions(int id, int userId, CancellationToken ct) + { + var project = await projectService.FindByIdAsync(id, ct); + if (project is null) return NotFound(); + + await projectService.RemoveUserPermissionsAsync(id, userId, ct); + return NoContent(); + } +} diff --git a/src/api/MicCheck.Api/Projects/SetUserPermissionsRequest.cs b/src/api/MicCheck.Api/Projects/SetUserPermissionsRequest.cs old mode 100644 new mode 100755 index 4023f00..047d948 --- a/src/api/MicCheck.Api/Projects/SetUserPermissionsRequest.cs +++ b/src/api/MicCheck.Api/Projects/SetUserPermissionsRequest.cs @@ -1,17 +1,17 @@ -using FluentValidation; -using MicCheck.Api.Authorization; - -namespace MicCheck.Api.Projects; - -public record SetUserPermissionsRequest(int UserId, bool IsAdmin, List Permissions); - -public class SetUserPermissionsRequestValidator : AbstractValidator -{ - public SetUserPermissionsRequestValidator() - { - RuleFor(x => x.UserId).GreaterThan(0); - RuleForEach(x => x.Permissions) - .Must(p => Enum.TryParse(p, true, out _)) - .WithMessage("Invalid permission value."); - } -} +using FluentValidation; +using MicCheck.Api.Common.Security.Authorization; + +namespace MicCheck.Api.Projects; + +public record SetUserPermissionsRequest(int UserId, bool IsAdmin, List Permissions); + +public class SetUserPermissionsRequestValidator : AbstractValidator +{ + public SetUserPermissionsRequestValidator() + { + RuleFor(x => x.UserId).GreaterThan(0); + RuleForEach(x => x.Permissions) + .Must(p => Enum.TryParse(p, true, out _)) + .WithMessage("Invalid permission value."); + } +} diff --git a/src/api/MicCheck.Api/Projects/UpdateProjectRequest.cs b/src/api/MicCheck.Api/Projects/UpdateProjectRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Properties/launchSettings.json b/src/api/MicCheck.Api/Properties/launchSettings.json old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/CreateSegmentRequest.cs b/src/api/MicCheck.Api/Segments/CreateSegmentRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/Segment.cs b/src/api/MicCheck.Api/Segments/Segment.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentCondition.cs b/src/api/MicCheck.Api/Segments/SegmentCondition.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentEvaluator.cs b/src/api/MicCheck.Api/Segments/SegmentEvaluator.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentResponse.cs b/src/api/MicCheck.Api/Segments/SegmentResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentRule.cs b/src/api/MicCheck.Api/Segments/SegmentRule.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentService.cs b/src/api/MicCheck.Api/Segments/SegmentService.cs old mode 100644 new mode 100755 index 16d2e4d..e111340 --- a/src/api/MicCheck.Api/Segments/SegmentService.cs +++ b/src/api/MicCheck.Api/Segments/SegmentService.cs @@ -5,15 +5,9 @@ using Microsoft.EntityFrameworkCore; namespace MicCheck.Api.Segments; -public record SegmentConditionDefinition( - string Property, - SegmentConditionOperator Operator, - string Value); +public record SegmentConditionDefinition(string Property, SegmentConditionOperator Operator, string Value); -public record SegmentRuleDefinition( - SegmentRuleType Type, - IReadOnlyList Conditions, - IReadOnlyList? ChildRules = null); +public record SegmentRuleDefinition(SegmentRuleType Type, IReadOnlyList Conditions, IReadOnlyList? ChildRules = null); public class SegmentService(MicCheckDbContext db, AuditService auditService) { @@ -37,11 +31,7 @@ public class SegmentService(MicCheckDbContext db, AuditService auditService) .FirstOrDefaultAsync(s => s.Id == id, ct); } - public async Task CreateAsync( - int projectId, - string name, - IReadOnlyList rules, - CancellationToken ct = default) + public async Task CreateAsync(int projectId, string name, IReadOnlyList rules, CancellationToken ct = default) { var count = await db.Segments.CountAsync(s => s.ProjectId == projectId, ct); if (count >= MaxSegmentsPerProject) @@ -75,11 +65,7 @@ public class SegmentService(MicCheckDbContext db, AuditService auditService) return segment; } - public async Task UpdateAsync( - int id, - string name, - IReadOnlyList rules, - CancellationToken ct = default) + public async Task UpdateAsync(int id, string name, IReadOnlyList rules, CancellationToken ct = default) { var segment = await db.Segments .Include(s => s.Rules) diff --git a/src/api/MicCheck.Api/Segments/SegmentSummaryResponse.cs b/src/api/MicCheck.Api/Segments/SegmentSummaryResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Segments/SegmentsController.cs b/src/api/MicCheck.Api/Segments/SegmentsController.cs old mode 100644 new mode 100755 index 0f26b15..e5e62bf --- a/src/api/MicCheck.Api/Segments/SegmentsController.cs +++ b/src/api/MicCheck.Api/Segments/SegmentsController.cs @@ -1,90 +1,89 @@ -using MicCheck.Api.Authorization; -using MicCheck.Api.Common; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.RateLimiting; - -namespace MicCheck.Api.Segments; - -[ApiController] -[Route("api/v1/projects/{projectId}/segments")] -[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] -[EnableRateLimiting("AdminApi")] -public class SegmentsController(SegmentService segmentService) : ControllerBase -{ - [HttpGet] - public async Task>> List( - int projectId, - [FromQuery] int page = 1, - [FromQuery] int pageSize = 20, - CancellationToken ct = default) - { - pageSize = Math.Clamp(pageSize, 1, 100); - var all = await segmentService.ListByProjectAsync(projectId, ct); - var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(SegmentResponse.From).ToList(); - return Ok(new PaginatedResponse(all.Count, null, null, paged)); - } - - [HttpPost] - public async Task> Create( - int projectId, CreateSegmentRequest request, CancellationToken ct) - { - try - { - var rules = MapRules(request.Rules); - var segment = await segmentService.CreateAsync(projectId, request.Name, rules, ct); - return CreatedAtAction(nameof(GetById), new { projectId, id = segment.Id }, SegmentResponse.From(segment)); - } - catch (DomainException ex) - { - return BadRequest(new { error = ex.Message }); - } - } - - [HttpGet("{id}")] - public async Task> GetById(int projectId, int id, CancellationToken ct) - { - var segment = await segmentService.FindByIdAsync(id, ct); - if (segment is null || segment.ProjectId != projectId) return NotFound(); - return Ok(SegmentResponse.From(segment)); - } - - [HttpPut("{id}")] - public async Task> Update( - int projectId, int id, CreateSegmentRequest request, CancellationToken ct) - { - var segment = await segmentService.FindByIdAsync(id, ct); - if (segment is null || segment.ProjectId != projectId) return NotFound(); - - try - { - var rules = MapRules(request.Rules); - var updated = await segmentService.UpdateAsync(id, request.Name, rules, ct); - return Ok(SegmentResponse.From(updated)); - } - catch (DomainException ex) - { - return BadRequest(new { error = ex.Message }); - } - } - - [HttpDelete("{id}")] - public async Task Delete(int projectId, int id, CancellationToken ct) - { - var segment = await segmentService.FindByIdAsync(id, ct); - if (segment is null || segment.ProjectId != projectId) return NotFound(); - - await segmentService.DeleteAsync(id, ct); - return NoContent(); - } - - private static IReadOnlyList MapRules(IReadOnlyList rules) => - rules.Select(r => new SegmentRuleDefinition( - Enum.Parse(r.Type, ignoreCase: true), - r.Conditions.Select(c => new SegmentConditionDefinition( - c.Property, - Enum.Parse(c.Operator, ignoreCase: true), - c.Value)).ToList(), - r.ChildRules is not null ? MapRules(r.ChildRules) : null - )).ToList(); -} +using MicCheck.Api.Common.Security.Authorization; +using MicCheck.Api.Common; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Segments; + +[ApiController] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class SegmentsController(SegmentService segmentService) : ControllerBase +{ + [HttpGet("api/v1/project/{projectId}/segments")] + public async Task>> List( + int projectId, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20, + CancellationToken ct = default) + { + pageSize = Math.Clamp(pageSize, 1, 100); + var all = await segmentService.ListByProjectAsync(projectId, ct); + var paged = all.Skip((page - 1) * pageSize).Take(pageSize).Select(SegmentResponse.From).ToList(); + return Ok(new PaginatedResponse(all.Count, null, null, paged)); + } + + [HttpPost("api/v1/project/{projectId}/segments")] + public async Task> Create( + int projectId, CreateSegmentRequest request, CancellationToken ct) + { + try + { + var rules = MapRules(request.Rules); + var segment = await segmentService.CreateAsync(projectId, request.Name, rules, ct); + return CreatedAtAction(nameof(GetById), new { projectId, id = segment.Id }, SegmentResponse.From(segment)); + } + catch (DomainException ex) + { + return BadRequest(new { error = ex.Message }); + } + } + + [HttpGet("api/v1/project/{projectId}/segment/{id}")] + public async Task> GetById(int projectId, int id, CancellationToken ct) + { + var segment = await segmentService.FindByIdAsync(id, ct); + if (segment is null || segment.ProjectId != projectId) return NotFound(); + return Ok(SegmentResponse.From(segment)); + } + + [HttpPut("api/v1/project/{projectId}/segment/{id}")] + public async Task> Update( + int projectId, int id, CreateSegmentRequest request, CancellationToken ct) + { + var segment = await segmentService.FindByIdAsync(id, ct); + if (segment is null || segment.ProjectId != projectId) return NotFound(); + + try + { + var rules = MapRules(request.Rules); + var updated = await segmentService.UpdateAsync(id, request.Name, rules, ct); + return Ok(SegmentResponse.From(updated)); + } + catch (DomainException ex) + { + return BadRequest(new { error = ex.Message }); + } + } + + [HttpDelete("api/v1/project/{projectId}/segment/{id}")] + public async Task Delete(int projectId, int id, CancellationToken ct) + { + var segment = await segmentService.FindByIdAsync(id, ct); + if (segment is null || segment.ProjectId != projectId) return NotFound(); + + await segmentService.DeleteAsync(id, ct); + return NoContent(); + } + + private static IReadOnlyList MapRules(IReadOnlyList rules) => + rules.Select(r => new SegmentRuleDefinition( + Enum.Parse(r.Type, ignoreCase: true), + r.Conditions.Select(c => new SegmentConditionDefinition( + c.Property, + Enum.Parse(c.Operator, ignoreCase: true), + c.Value)).ToList(), + r.ChildRules is not null ? MapRules(r.ChildRules) : null + )).ToList(); +} diff --git a/src/api/MicCheck.Api/Users/ChangePasswordRequest.cs b/src/api/MicCheck.Api/Users/ChangePasswordRequest.cs new file mode 100755 index 0000000..a0f49a1 --- /dev/null +++ b/src/api/MicCheck.Api/Users/ChangePasswordRequest.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Users; + +public record ChangePasswordRequest(string CurrentPassword, string NewPassword); diff --git a/src/api/MicCheck.Api/Users/RefreshToken.cs b/src/api/MicCheck.Api/Users/RefreshToken.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Users/UpdateProfileRequest.cs b/src/api/MicCheck.Api/Users/UpdateProfileRequest.cs new file mode 100755 index 0000000..87b662b --- /dev/null +++ b/src/api/MicCheck.Api/Users/UpdateProfileRequest.cs @@ -0,0 +1,3 @@ +namespace MicCheck.Api.Users; + +public record UpdateProfileRequest(string FirstName, string LastName, string Email); diff --git a/src/api/MicCheck.Api/Users/User.cs b/src/api/MicCheck.Api/Users/User.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Users/UserResponse.cs b/src/api/MicCheck.Api/Users/UserResponse.cs new file mode 100755 index 0000000..36cb139 --- /dev/null +++ b/src/api/MicCheck.Api/Users/UserResponse.cs @@ -0,0 +1,13 @@ +namespace MicCheck.Api.Users; + +public record UserResponse( + int Id, + string Email, + string FirstName, + string LastName, + DateTimeOffset CreatedAt, + DateTimeOffset? LastLoginAt) +{ + public static UserResponse From(User user) => + new(user.Id, user.Email, user.FirstName, user.LastName, user.CreatedAt, user.LastLoginAt); +} diff --git a/src/api/MicCheck.Api/Users/UserService.cs b/src/api/MicCheck.Api/Users/UserService.cs new file mode 100755 index 0000000..d731e48 --- /dev/null +++ b/src/api/MicCheck.Api/Users/UserService.cs @@ -0,0 +1,44 @@ +using MicCheck.Api.Data; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +namespace MicCheck.Api.Users; + +public class UserService(MicCheckDbContext db, IPasswordHasher passwordHasher) +{ + public async Task FindByIdAsync(int userId, CancellationToken ct = default) => + await db.Users.FirstOrDefaultAsync(u => u.Id == userId && u.IsActive, ct); + + public async Task<(User? User, bool EmailConflict)> UpdateProfileAsync( + int userId, string firstName, string lastName, string email, CancellationToken ct = default) + { + var user = await db.Users.FirstOrDefaultAsync(u => u.Id == userId && u.IsActive, ct); + if (user is null) return (null, false); + + if (!string.Equals(user.Email, email, StringComparison.OrdinalIgnoreCase)) + { + var emailTaken = await db.Users.AnyAsync(u => u.Email == email && u.Id != userId, ct); + if (emailTaken) return (null, true); + } + + user.FirstName = firstName; + user.LastName = lastName; + user.Email = email; + await db.SaveChangesAsync(ct); + return (user, false); + } + + public async Task ChangePasswordAsync( + int userId, string currentPassword, string newPassword, CancellationToken ct = default) + { + var user = await db.Users.FirstOrDefaultAsync(u => u.Id == userId && u.IsActive, ct); + if (user is null) return false; + + var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, currentPassword); + if (result == PasswordVerificationResult.Failed) return false; + + user.PasswordHash = passwordHasher.HashPassword(user, newPassword); + await db.SaveChangesAsync(ct); + return true; + } +} diff --git a/src/api/MicCheck.Api/Users/UsersController.cs b/src/api/MicCheck.Api/Users/UsersController.cs new file mode 100755 index 0000000..520de74 --- /dev/null +++ b/src/api/MicCheck.Api/Users/UsersController.cs @@ -0,0 +1,67 @@ +using MicCheck.Api.Common.Security.Authorization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; + +namespace MicCheck.Api.Users; + +[ApiController] +[Route("api/v1/user")] +[Authorize(Policy = AuthorizationPolicies.AdminApiAccess)] +[EnableRateLimiting("AdminApi")] +public class UsersController(UserService userService) : ControllerBase +{ + [HttpGet("{id:int}")] + public async Task> GetById(int id, CancellationToken ct) + { + var user = await userService.FindByIdAsync(id, ct); + return user is null ? NotFound() : Ok(UserResponse.From(user)); + } + + [HttpGet("me")] + public async Task> GetMe(CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + var user = await userService.FindByIdAsync(userId.Value, ct); + return user is null ? NotFound() : Ok(UserResponse.From(user)); + } + + [HttpPut("me")] + public async Task> UpdateMe(UpdateProfileRequest request, CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + if (string.IsNullOrWhiteSpace(request.FirstName) || + string.IsNullOrWhiteSpace(request.LastName) || + string.IsNullOrWhiteSpace(request.Email)) + return BadRequest("First name, last name, and email are required."); + + var (user, emailConflict) = await userService.UpdateProfileAsync( + userId.Value, request.FirstName.Trim(), request.LastName.Trim(), request.Email.Trim(), ct); + + if (emailConflict) return Conflict("Email is already in use."); + return user is null ? NotFound() : Ok(UserResponse.From(user)); + } + + [HttpPost("me/change-password")] + public async Task ChangePassword(ChangePasswordRequest request, CancellationToken ct) + { + var userId = GetCurrentUserId(); + if (userId is null) return Unauthorized(); + + if (string.IsNullOrWhiteSpace(request.CurrentPassword) || string.IsNullOrWhiteSpace(request.NewPassword)) + return BadRequest("Current and new passwords are required."); + + var success = await userService.ChangePasswordAsync(userId.Value, request.CurrentPassword, request.NewPassword, ct); + return success ? NoContent() : BadRequest("Current password is incorrect."); + } + + private int? GetCurrentUserId() + { + var claim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; + return int.TryParse(claim, out var id) ? id : null; + } +} diff --git a/src/api/MicCheck.Api/Webhooks/CreateWebhookRequest.cs b/src/api/MicCheck.Api/Webhooks/CreateWebhookRequest.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/Webhook.cs b/src/api/MicCheck.Api/Webhooks/Webhook.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookBackgroundService.cs b/src/api/MicCheck.Api/Webhooks/WebhookBackgroundService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookDeliveryLog.cs b/src/api/MicCheck.Api/Webhooks/WebhookDeliveryLog.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookDeliveryLogResponse.cs b/src/api/MicCheck.Api/Webhooks/WebhookDeliveryLogResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookDispatcher.cs b/src/api/MicCheck.Api/Webhooks/WebhookDispatcher.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookEvent.cs b/src/api/MicCheck.Api/Webhooks/WebhookEvent.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookPayload.cs b/src/api/MicCheck.Api/Webhooks/WebhookPayload.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookQueue.cs b/src/api/MicCheck.Api/Webhooks/WebhookQueue.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookResponse.cs b/src/api/MicCheck.Api/Webhooks/WebhookResponse.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookRetryBackgroundService.cs b/src/api/MicCheck.Api/Webhooks/WebhookRetryBackgroundService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/Webhooks/WebhookService.cs b/src/api/MicCheck.Api/Webhooks/WebhookService.cs old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/appsettings.Development.json b/src/api/MicCheck.Api/appsettings.Development.json old mode 100644 new mode 100755 diff --git a/src/api/MicCheck.Api/appsettings.json b/src/api/MicCheck.Api/appsettings.json old mode 100644 new mode 100755 diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/bug.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/bug.yml new file mode 100755 index 0000000..651be6c --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,37 @@ +name: Bug 🐞 +description: Report a bug +labels: [support, bug] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! ☺️ + - type: textarea + attributes: + label: Steps to reproduce + validations: + required: true + - type: textarea + attributes: + label: What is expected? + validations: + required: true + - type: textarea + attributes: + label: What is actually happening? + validations: + required: true + - type: textarea + attributes: + label: Additional data + value: | + + + diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/config.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/config.yml new file mode 100755 index 0000000..ec4bb38 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false \ No newline at end of file diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/feature-request.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100755 index 0000000..827311a --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,18 @@ +name: Feature request ✨ +description: Suggest an idea or ask for a feature that you would like to have +labels: [support, feature-req] +body: + - type: markdown + attributes: + value: | + Thanks for letting us know how we can improve our product! ☺️ + - type: textarea + attributes: + label: What problem does this feature solve? + validations: + required: true + - type: textarea + attributes: + label: What does the proposed solution look like? + validations: + required: true diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/deploy-demos.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/deploy-demos.yml new file mode 100755 index 0000000..85b3ebe --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/deploy-demos.yml @@ -0,0 +1,51 @@ +name: 🚀 Deploy Demo + +on: [workflow_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: ⚙️ Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 8 + + - name: ⚙️ Set BRAND_NAME environment variable from repo name + run: echo BRAND_NAME=${{ github.event.repository.name }} | cut -d '-' -f1 >> $GITHUB_ENV + + - name: ⬇️ Clone current repo under //vue-free + uses: actions/checkout@v4 + with: + path: ${{ env.BRAND_NAME }}/vue-free + + - name: ⬇️ Clone automation scripts repo under /automation-scripts + uses: actions/checkout@v4 + with: + repository: themeselection/automation-scripts + token: ${{ secrets.GH_PAT }} + path: automation-scripts + + - name: ⬇️ Install packages in automation-scripts dir + working-directory: automation-scripts/vue + run: pnpm install + + - name: ⚙️ Prepare free demo + working-directory: automation-scripts/vue + run: pnpm tsx src/templates/${{ env.BRAND_NAME }}/scripts/prepareVueFreeDemo.ts + + - name: 📦 Generate demo + working-directory: ${{ env.BRAND_NAME }}/vue-free/typescript-version + run: pnpm i && pnpm build --base=/${{ env.BRAND_NAME }}-vuetify-vuejs-admin-template-free/demo/ + + - name: 🚀 Upload demo + uses: appleboy/scp-action@master + with: + HOST: ${{ secrets.HOST }} + USERNAME: ${{ secrets.USERNAME }} + PORT: ${{ secrets.PORT }} + KEY: ${{ secrets.SSHKEY }} + source: ${{ env.BRAND_NAME }}/vue-free/typescript-version/dist + target: ${{ secrets.PROD_DIR }}/demo + rm: true + strip_components: 4 diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue-comment.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue-comment.yml new file mode 100755 index 0000000..83687ac --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue-comment.yml @@ -0,0 +1,14 @@ +name: 'Handle new issue comment' +on: + issue_comment: + types: [created] + +jobs: + handle_new_issue_comment: + runs-on: ubuntu-latest + name: Handle new issue comment + steps: + - name: Toggle awaiting-reply label + uses: jd-solanki/gh-action-toggle-awaiting-reply-label@v2.1.0 + with: + label: awaiting-reply diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue.yml new file mode 100755 index 0000000..d338fe2 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/handle-new-issue.yml @@ -0,0 +1,19 @@ +name: 'Handle new issue' +on: + issues: + types: [opened] + +jobs: + handle_new_issue: + runs-on: ubuntu-latest + name: Handle new issue + steps: + - name: Find duplicates + uses: wow-actions/potential-duplicates@v1.0.8 + with: + GITHUB_TOKEN: ${{ github.token }} + label: duplicate + comment: > + Potential duplicates: {{#issues}} + - #{{ number }} _({{ accuracy }}% Match)_ + {{/issues}} \ No newline at end of file diff --git a/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/issue-staler.yml b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/issue-staler.yml new file mode 100755 index 0000000..534dc57 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.github/workflows/issue-staler.yml @@ -0,0 +1,18 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v4 + with: + stale-issue-message: 'This issue has been automatically marked as stale because it has no recent activity. It will be closed if no further activity occurs. Thank you for raising the concern.' + close-issue-message: 'This issue has been automatically marked as closed because it has no recent activity.' + stale-issue-label: 'stale' + only-labels: 'awaiting-reply' + exempt-issue-labels: 'triage' + days-before-stale: 7 + days-before-close: 7 diff --git a/src/materio-vuetify-vuejs-admin-template-free/.gitignore b/src/materio-vuetify-vuejs-admin-template-free/.gitignore new file mode 100755 index 0000000..3c3629e --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/src/materio-vuetify-vuejs-admin-template-free/CHANGELOG.md b/src/materio-vuetify-vuejs-admin-template-free/CHANGELOG.md new file mode 100755 index 0000000..3a705e6 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/CHANGELOG.md @@ -0,0 +1,87 @@ + + +# Changelog + +All notable changes to this template will be documented in this file + +## v2.3.0 (2025-01-01) + +### Updated + +- Updated Vue & Vuetify to the latest version + +## v2.2.2 (2024-07-29) + +### Updated + +- Updated all the libraries to the latest version + +## v2.2.1 (2024-01-05) + +### Added + +- Added Hire Us file +- Added Documentation File + +## v2.2.0 (2024-01-04) + +### Updated + +- Updated all dependencies and devDependencies to latest + +### Added + +- Added Remix Icons + +### Removed + +- Material Design icons removed + +## v2.1.0 (2023-05-26) + +### Updated + +- Updated repo according to pro template +- Use Vuetify's official release instead of BETA + +## v2.0.0 (2022-10-15) + +### Added + +- Vue 3 version added +- Vuetify 3 support added +- TypeScript version added (Vue 3 only) + +## v1.0.3 (2021-11-12) + +### Updated + +- Updated [@vue/composition-api](https://github.com/vuejs/composition-api) package to v1.3.3 to mitigate composition api error + +## v1.0.2 (2021-08-18) + +### Fixed + +- broken links updated in footer + +## Updates + +- "Basic Cards" page renamed to "Cards" +- `README.md` updated + +## v1.0.1 (2021-08-13) + +### Fixed + +- Fixed missing fonts + branding updated + +### Updated + +- public path updated in `vue.config.js` +- `README.md` updated + +## v1.0.0 (2021-08-13) + +### Added + +- Initial Release diff --git a/src/materio-vuetify-vuejs-admin-template-free/LICENSE b/src/materio-vuetify-vuejs-admin-template-free/LICENSE new file mode 100755 index 0000000..16781c6 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 ThemeSelection + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/materio-vuetify-vuejs-admin-template-free/README.md b/src/materio-vuetify-vuejs-admin-template-free/README.md new file mode 100755 index 0000000..150f9f7 --- /dev/null +++ b/src/materio-vuetify-vuejs-admin-template-free/README.md @@ -0,0 +1,197 @@ +

+ +

+ + materio-logo + +

+ +

+ + Materio – Vuetify Vuejs Admin Template Free + +

+ +

Production Ready, Carefully Crafted, Extensive Vuetifty Admin Template

+ +

+ + license + + GitHub Workflow Status + + GitHub release + + + Twitter Follow + +

+ +[![Materio – Vuetify Vuejs Admin Template Demo Screenshot](https://cdn.themeselection.com/ts-assets/materio/materio-vuetify-vuejs-admin-template-free/banner/banner.png)](https://themeselection.com/item/materio-free-vuetify-vuejs-admin-template/) + +## Introduction 🚀 + +If you're a developer looking for an admin dashboard that is developer-friendly, rich with features, and highly customizable look no further than Materio. We've followed the highest industry standards to bring you the very best [Vue Admin Template](https://themeselection.com/item/category/vuejs-admin-templates/) that is not only fast and easy to use but highly scalable. Offering ultimate convenience and flexibility, you'll be able to build whatever application you want with very little hassle. + +- ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite 3](https://github.com/vitejs/vite) & [Vuetify 3](https://next.vuetifyjs.com/en/) - Uses the latest Vuetify 3 +- 🗂 [File based routing](https://github.com/hannoeru/vite-plugin-pages) +- 📦 [Components auto importing](https://github.com/antfu/unplugin-vue-components) +- 📑 [Layout system](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) +- 😃 Use icons from any icon sets with classes by [Iconify](https://iconify.design/) +- 🌍 I18n ready +- 🔥 Use the [`", + "", + "", + "", + "", + "" + ], + "description": "Vue SFC Typescript" + }, + "template": { + "scope": "vue", + "prefix": "template", + "body": [ + "" + ], + "description": "Create