diff --git a/.github/workflows/cd-deploy.yml b/.github/workflows/cd-deploy.yml index d33d735..2c6aa68 100644 --- a/.github/workflows/cd-deploy.yml +++ b/.github/workflows/cd-deploy.yml @@ -16,7 +16,7 @@ jobs: name: Deploy to Production runs-on: self-hosted steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Execute deployment script run: | @@ -37,7 +37,7 @@ jobs: outputs: tag_name: ${{ steps.vars.outputs.tag_name }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Resolve version id: vars @@ -76,17 +76,17 @@ jobs: runs-on: windows-latest steps: - name: Checkout monorepo - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: recursive - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '22' - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' @@ -108,7 +108,7 @@ jobs: shell: pwsh - name: Attach installer to GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ needs.release.outputs.tag_name }} prerelease: false diff --git a/.github/workflows/ci-dev-to-qa.yml b/.github/workflows/ci-dev-to-qa.yml index bc2cf63..6ba2652 100644 --- a/.github/workflows/ci-dev-to-qa.yml +++ b/.github/workflows/ci-dev-to-qa.yml @@ -11,10 +11,10 @@ jobs: name: Unit Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' @@ -26,7 +26,7 @@ jobs: dotnet test TuColmadoRD.slnx -c Release --no-build --verbosity normal - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '22' @@ -46,7 +46,7 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Create and Merge PR to QA diff --git a/.github/workflows/ci-qa-to-main.yml b/.github/workflows/ci-qa-to-main.yml index 5c12f99..d4bad68 100644 --- a/.github/workflows/ci-qa-to-main.yml +++ b/.github/workflows/ci-qa-to-main.yml @@ -11,10 +11,10 @@ jobs: name: Integration Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' @@ -26,7 +26,7 @@ jobs: dotnet test TuColmadoRD.slnx -c Release --no-build --verbosity normal - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '22' @@ -46,7 +46,7 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Create and Merge PR to Main diff --git a/.github/workflows/ci-services.yml b/.github/workflows/ci-services.yml index a845d1d..93e1d77 100644 --- a/.github/workflows/ci-services.yml +++ b/.github/workflows/ci-services.yml @@ -38,8 +38,8 @@ jobs: reports: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.reports }} swarm: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.swarm }} steps: - - uses: actions/checkout@v4 - - uses: dorny/paths-filter@v3 + - uses: actions/checkout@v6 + - uses: dorny/paths-filter@v4 id: filter with: filters: | @@ -61,10 +61,10 @@ jobs: run: working-directory: services/catalog-service steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache Cargo - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.cargo/registry @@ -90,10 +90,10 @@ jobs: run: working-directory: services/reports-service steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache Cargo - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.cargo/registry @@ -124,11 +124,11 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set image metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/catalog-service tags: | @@ -137,17 +137,17 @@ jobs: type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Build and push catalog-service - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: services/catalog-service push: true @@ -166,11 +166,11 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set image metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/reports-service tags: | @@ -179,17 +179,17 @@ jobs: type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Build and push reports-service - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: services/reports-service push: true @@ -211,10 +211,10 @@ jobs: runs-on: ubuntu-latest environment: production steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Copy Swarm configs to VPS - uses: appleboy/scp-action@v0.1.7 + uses: appleboy/scp-action@v1.0.0 with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} @@ -224,7 +224,7 @@ jobs: strip_components: 2 - name: Deploy via SSH - uses: appleboy/ssh-action@v1.0.3 + uses: appleboy/ssh-action@v1.2.5 with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml index f9dfc54..be9a8fb 100644 --- a/.github/workflows/release-test.yml +++ b/.github/workflows/release-test.yml @@ -17,10 +17,10 @@ jobs: steps: - name: Checkout monorepo - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: node-version: '22' @@ -76,14 +76,14 @@ jobs: shell: pwsh - name: Upload installer artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: installer-${{ steps.vars.outputs.app_version }} path: backend/publish/installer/*.exe if-no-files-found: error - name: Create GitHub prerelease - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ github.ref_name }} name: TuColmadoRD ${{ github.ref_name }} - Test Release diff --git a/Dockerfile b/Dockerfile index 9d68ff3..06cf967 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # Run: docker run -p 5032:5032 -e DB_HOST=... tucolmadord # ─── Stage 1: Build .NET gateway and API ────────────────────────────────────── -FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build +FROM mcr.microsoft.com/dotnet/sdk:11.0-preview AS build WORKDIR /source # Copy solution and all project files first for layer caching @@ -29,7 +29,7 @@ RUN dotnet publish backend/src/Presentations/TuColmadoRD.ApiGateway/TuColmadoRD. -c Release -o /app/gateway # ─── Stage 2: Runtime image ─────────────────────────────────────────────────── -FROM mcr.microsoft.com/dotnet/aspnet:10.0-preview AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:11.0-preview AS runtime WORKDIR /app RUN apt-get update && apt-get install -y supervisor && rm -rf /var/lib/apt/lists/* diff --git a/auth/package.json b/auth/package.json index 18d79cf..a7d47f6 100644 --- a/auth/package.json +++ b/auth/package.json @@ -16,11 +16,11 @@ "dependencies": { "bcryptjs": "^3.0.3", "cors": "^2.8.6", - "dotenv": "^17.3.1", + "dotenv": "^17.4.2", "express": "^5.2.1", "helmet": "^8.1.0", "jsonwebtoken": "^9.0.3", - "mongoose": "^9.3.2", + "mongoose": "^9.6.2", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1" }, diff --git a/auth/pnpm-lock.yaml b/auth/pnpm-lock.yaml index 74dc9d4..d4310aa 100644 --- a/auth/pnpm-lock.yaml +++ b/auth/pnpm-lock.yaml @@ -1,4452 +1,4451 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - bcryptjs: - specifier: ^3.0.3 - version: 3.0.3 - cors: - specifier: ^2.8.6 - version: 2.8.6 - dotenv: - specifier: ^17.3.1 - version: 17.3.1 - express: - specifier: ^5.2.1 - version: 5.2.1 - helmet: - specifier: ^8.1.0 - version: 8.1.0 - jsonwebtoken: - specifier: ^9.0.3 - version: 9.0.3 - mongoose: - specifier: ^9.3.2 - version: 9.3.2 - swagger-jsdoc: - specifier: ^6.2.8 - version: 6.2.8(openapi-types@12.1.3) - swagger-ui-express: - specifier: ^5.0.1 - version: 5.0.1(express@5.2.1) - devDependencies: - '@types/cors': - specifier: ^2.8.19 - version: 2.8.19 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 - '@types/jest': - specifier: ^30.0.0 - version: 30.0.0 - '@types/jsonwebtoken': - specifier: ^9.0.10 - version: 9.0.10 - '@types/node': - specifier: ^25.5.0 - version: 25.5.0 - '@types/pg': - specifier: ^8.20.0 - version: 8.20.0 - '@types/swagger-jsdoc': - specifier: ^6.0.4 - version: 6.0.4 - '@types/swagger-ui-express': - specifier: ^4.1.8 - version: 4.1.8 - jest: - specifier: ^30.3.0 - version: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - pg: - specifier: ^8.20.0 - version: 8.20.0 - ts-jest: - specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)))(typescript@6.0.2) - ts-node-dev: - specifier: ^2.0.0 - version: 2.0.0(@types/node@25.5.0)(typescript@6.0.2) - typescript: - specifier: ^6.0.2 - version: 6.0.2 - -packages: - - '@apidevtools/json-schema-ref-parser@9.1.2': - resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==} - - '@apidevtools/openapi-schemas@2.1.0': - resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} - engines: {node: '>=10'} - - '@apidevtools/swagger-methods@3.0.2': - resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} - - '@apidevtools/swagger-parser@10.0.3': - resolution: {integrity: sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==} - peerDependencies: - openapi-types: '>=7' - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-syntax-async-generators@7.8.4': - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-bigint@7.8.3': - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-properties@7.12.13': - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-static-block@7.14.5': - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-attributes@7.28.6': - resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-json-strings@7.8.3': - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4': - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-numeric-separator@7.10.4': - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-object-rest-spread@7.8.3': - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3': - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-private-property-in-object@7.14.5': - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-top-level-await@7.14.5': - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@bcoe/v8-coverage@0.2.3': - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - - '@jest/console@30.3.0': - resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/core@30.3.0': - resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - '@jest/diff-sequences@30.3.0': - resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/environment@30.3.0': - resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/expect-utils@30.3.0': - resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/expect@30.3.0': - resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/fake-timers@30.3.0': - resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/get-type@30.1.0': - resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/globals@30.3.0': - resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/pattern@30.0.1': - resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/reporters@30.3.0': - resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - '@jest/schemas@30.0.5': - resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/snapshot-utils@30.3.0': - resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/source-map@30.0.1': - resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/test-result@30.3.0': - resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/test-sequencer@30.3.0': - resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/transform@30.3.0': - resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/types@30.3.0': - resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} - - '@mongodb-js/saslprep@1.4.6': - resolution: {integrity: sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==} - - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@scarf/scarf@1.4.0': - resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - - '@sinclair/typebox@0.34.49': - resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@15.1.1': - resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==} - - '@tsconfig/node10@1.0.12': - resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/cors@2.8.19': - resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} - - '@types/express-serve-static-core@5.1.1': - resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - - '@types/express@5.0.6': - resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} - - '@types/http-errors@2.0.5': - resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - - '@types/jest@30.0.0': - resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/jsonwebtoken@9.0.10': - resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} - - '@types/pg@8.20.0': - resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} - - '@types/qs@6.15.0': - resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/send@1.2.1': - resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - - '@types/serve-static@2.2.0': - resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - - '@types/stack-utils@2.0.3': - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - - '@types/strip-bom@3.0.0': - resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==} - - '@types/strip-json-comments@0.0.30': - resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==} - - '@types/swagger-jsdoc@6.0.4': - resolution: {integrity: sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==} - - '@types/swagger-ui-express@4.1.8': - resolution: {integrity: sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==} - - '@types/webidl-conversions@7.0.3': - resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} - - '@types/whatwg-url@13.0.0': - resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.35': - resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} - cpu: [arm] - os: [android] - - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} - cpu: [arm64] - os: [android] - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} - cpu: [arm64] - os: [darwin] - - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} - cpu: [x64] - os: [darwin] - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} - cpu: [x64] - os: [freebsd] - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} - cpu: [arm64] - os: [win32] - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} - cpu: [ia32] - os: [win32] - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} - cpu: [x64] - os: [win32] - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - acorn-walk@8.3.5: - resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} - engines: {node: '>=0.4.0'} - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - babel-jest@30.3.0: - resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@babel/core': ^7.11.0 || ^8.0.0-0 - - babel-plugin-istanbul@7.0.1: - resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} - engines: {node: '>=12'} - - babel-plugin-jest-hoist@30.3.0: - resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - babel-preset-current-node-syntax@1.2.0: - resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} - peerDependencies: - '@babel/core': ^7.0.0 || ^8.0.0-0 - - babel-preset-jest@30.3.0: - resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@babel/core': ^7.11.0 || ^8.0.0-beta.1 - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - baseline-browser-mapping@2.10.12: - resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - bcryptjs@3.0.3: - resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} - hasBin: true - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.3: - resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - - bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - - bson@7.2.0: - resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} - engines: {node: '>=20.19.0'} - - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - call-me-maybe@1.0.2: - resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001781: - resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - ci-info@4.4.0: - resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} - engines: {node: '>=8'} - - cjs-module-lexer@2.2.0: - resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - collect-v8-coverage@1.0.3: - resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - commander@6.2.0: - resolution: {integrity: sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - dedent@1.7.2: - resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - dynamic-dedupe@0.3.0: - resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.328: - resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==} - - emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - - exit-x@0.2.2: - resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} - engines: {node: '>= 0.8.0'} - - expect@30.3.0: - resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob@10.5.0: - resolution: {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 - hasBin: true - - glob@7.1.6: - resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} - 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 - - glob@7.2.3: - resolution: {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 - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - handlebars@4.7.9: - resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} - engines: {node: '>=0.4.7'} - hasBin: true - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - helmet@8.1.0: - resolution: {integrity: sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==} - engines: {node: '>=18.0.0'} - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - import-local@3.2.0: - resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} - engines: {node: '>=8'} - hasBin: true - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {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. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jest-changed-files@30.3.0: - resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-circus@30.3.0: - resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-cli@30.3.0: - resolution: {integrity: sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - jest-config@30.3.0: - resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@types/node': '*' - esbuild-register: '>=3.4.0' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - esbuild-register: - optional: true - ts-node: - optional: true - - jest-diff@30.3.0: - resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-docblock@30.2.0: - resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-each@30.3.0: - resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-environment-node@30.3.0: - resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-haste-map@30.3.0: - resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-leak-detector@30.3.0: - resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-matcher-utils@30.3.0: - resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-message-util@30.3.0: - resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-mock@30.3.0: - resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-pnp-resolver@1.2.3: - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - - jest-regex-util@30.0.1: - resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-resolve-dependencies@30.3.0: - resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-resolve@30.3.0: - resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-runner@30.3.0: - resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-runtime@30.3.0: - resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-snapshot@30.3.0: - resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-util@30.3.0: - resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-validate@30.3.0: - resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-watcher@30.3.0: - resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-worker@30.3.0: - resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest@30.3.0: - resolution: {integrity: sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} - hasBin: true - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonwebtoken@9.0.3: - resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} - engines: {node: '>=12', npm: '>=6'} - - jwa@2.0.1: - resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - - jws@4.0.1: - resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} - - kareem@3.2.0: - resolution: {integrity: sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==} - engines: {node: '>=18.0.0'} - - leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - - lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - - lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. - - lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - - lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - - makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - memory-pager@1.5.0: - resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - mongodb-connection-string-url@7.0.1: - resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} - engines: {node: '>=20.19.0'} - - mongodb@7.1.1: - resolution: {integrity: sha512-067DXiMjcpYQl6bGjWQoTUEE9UoRViTtKFcoqX7z08I+iDZv/emH1g8XEFiO3qiDfXAheT5ozl1VffDTKhIW/w==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@aws-sdk/credential-providers': ^3.806.0 - '@mongodb-js/zstd': ^7.0.0 - gcp-metadata: ^7.0.1 - kerberos: ^7.0.0 - mongodb-client-encryption: '>=7.0.0 <7.1.0' - snappy: ^7.3.2 - socks: ^2.8.6 - peerDependenciesMeta: - '@aws-sdk/credential-providers': - optional: true - '@mongodb-js/zstd': - optional: true - gcp-metadata: - optional: true - kerberos: - optional: true - mongodb-client-encryption: - optional: true - snappy: - optional: true - socks: - optional: true - - mongoose@9.3.2: - resolution: {integrity: sha512-4hMJA4vLAeNG6LnDwJImPYM+uJMVw+sFs7jtS/91OKOT7rzv19ytAAeswtAdWoinVBUVrzmClL/ZoPhcU5RL8w==} - engines: {node: '>=20.19.0'} - - mpath@0.9.0: - resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} - engines: {node: '>=4.0.0'} - - mquery@6.0.0: - resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==} - engines: {node: '>=20.19.0'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - napi-postinstall@0.3.4: - resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - - node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - openapi-types@12.1.3: - resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - - pg-cloudflare@1.3.0: - resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - - pg-connection-string@2.12.0: - resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-pool@3.13.0: - resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.13.0: - resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg@8.20.0: - resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - - pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.1: - resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - - pretty-format@30.3.0: - resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - pure-rand@7.0.1: - resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} - engines: {node: '>=0.6'} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - sift@17.1.3: - resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - sparse-bitfield@3.0.3: - resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - swagger-jsdoc@6.2.8: - resolution: {integrity: sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==} - engines: {node: '>=12.0.0'} - hasBin: true - - swagger-parser@10.0.3: - resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==} - engines: {node: '>=10'} - - swagger-ui-dist@5.32.1: - resolution: {integrity: sha512-6HQoo7+j8PA2QqP5kgAb9dl1uxUjvR0SAoL/WUp1sTEvm0F6D5npgU2OGCLwl++bIInqGlEUQ2mpuZRZYtyCzQ==} - - swagger-ui-express@5.0.1: - resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} - engines: {node: '>= v0.10.32'} - peerDependencies: - express: '>=4.0.0 || >=5.0.0-beta' - - synckit@0.11.12: - resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} - engines: {node: ^14.18.0 || >=16.0.0} - - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - ts-jest@29.4.6: - resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} - engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - 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 - esbuild: '*' - 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 - - ts-node-dev@2.0.0: - resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} - engines: {node: '>=0.8.0'} - hasBin: true - peerDependencies: - node-notifier: '*' - typescript: '*' - peerDependenciesMeta: - node-notifier: - optional: true - - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - - tsconfig@7.0.0: - resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typescript@6.0.2: - resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} - engines: {node: '>=14.17'} - hasBin: true - - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - - v8-to-istanbul@9.3.0: - resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} - engines: {node: '>=10.12.0'} - - validator@13.15.26: - resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} - engines: {node: '>= 0.10'} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml@2.0.0-1: - resolution: {integrity: sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==} - engines: {node: '>= 6'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true - -snapshots: - - '@apidevtools/json-schema-ref-parser@9.1.2': - dependencies: - '@jsdevtools/ono': 7.1.3 - '@types/json-schema': 7.0.15 - call-me-maybe: 1.0.2 - js-yaml: 4.1.1 - - '@apidevtools/openapi-schemas@2.1.0': {} - - '@apidevtools/swagger-methods@3.0.2': {} - - '@apidevtools/swagger-parser@10.0.3(openapi-types@12.1.3)': - dependencies: - '@apidevtools/json-schema-ref-parser': 9.1.2 - '@apidevtools/openapi-schemas': 2.1.0 - '@apidevtools/swagger-methods': 3.0.2 - '@jsdevtools/ono': 7.1.3 - call-me-maybe: 1.0.2 - openapi-types: 12.1.3 - z-schema: 5.0.5 - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 - '@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.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.2': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@bcoe/v8-coverage@0.2.3': {} - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.9.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.2 - resolve-from: 5.0.0 - - '@istanbuljs/schema@0.1.3': {} - - '@jest/console@30.3.0': - dependencies: - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - chalk: 4.1.2 - jest-message-util: 30.3.0 - jest-util: 30.3.0 - slash: 3.0.0 - - '@jest/core@30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2))': - dependencies: - '@jest/console': 30.3.0 - '@jest/pattern': 30.0.1 - '@jest/reporters': 30.3.0 - '@jest/test-result': 30.3.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 4.4.0 - exit-x: 0.2.2 - graceful-fs: 4.2.11 - jest-changed-files: 30.3.0 - jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - jest-haste-map: 30.3.0 - jest-message-util: 30.3.0 - jest-regex-util: 30.0.1 - jest-resolve: 30.3.0 - jest-resolve-dependencies: 30.3.0 - jest-runner: 30.3.0 - jest-runtime: 30.3.0 - jest-snapshot: 30.3.0 - jest-util: 30.3.0 - jest-validate: 30.3.0 - jest-watcher: 30.3.0 - pretty-format: 30.3.0 - slash: 3.0.0 - transitivePeerDependencies: - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - - '@jest/diff-sequences@30.3.0': {} - - '@jest/environment@30.3.0': - dependencies: - '@jest/fake-timers': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - jest-mock: 30.3.0 - - '@jest/expect-utils@30.3.0': - dependencies: - '@jest/get-type': 30.1.0 - - '@jest/expect@30.3.0': - dependencies: - expect: 30.3.0 - jest-snapshot: 30.3.0 - transitivePeerDependencies: - - supports-color - - '@jest/fake-timers@30.3.0': - dependencies: - '@jest/types': 30.3.0 - '@sinonjs/fake-timers': 15.1.1 - '@types/node': 25.5.0 - jest-message-util: 30.3.0 - jest-mock: 30.3.0 - jest-util: 30.3.0 - - '@jest/get-type@30.1.0': {} - - '@jest/globals@30.3.0': - dependencies: - '@jest/environment': 30.3.0 - '@jest/expect': 30.3.0 - '@jest/types': 30.3.0 - jest-mock: 30.3.0 - transitivePeerDependencies: - - supports-color - - '@jest/pattern@30.0.1': - dependencies: - '@types/node': 25.5.0 - jest-regex-util: 30.0.1 - - '@jest/reporters@30.3.0': - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 30.3.0 - '@jest/test-result': 30.3.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.5.0 - chalk: 4.1.2 - collect-v8-coverage: 1.0.3 - exit-x: 0.2.2 - glob: 10.5.0 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.2.0 - jest-message-util: 30.3.0 - jest-util: 30.3.0 - jest-worker: 30.3.0 - slash: 3.0.0 - string-length: 4.0.2 - v8-to-istanbul: 9.3.0 - transitivePeerDependencies: - - supports-color - - '@jest/schemas@30.0.5': - dependencies: - '@sinclair/typebox': 0.34.49 - - '@jest/snapshot-utils@30.3.0': - dependencies: - '@jest/types': 30.3.0 - chalk: 4.1.2 - graceful-fs: 4.2.11 - natural-compare: 1.4.0 - - '@jest/source-map@30.0.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - callsites: 3.1.0 - graceful-fs: 4.2.11 - - '@jest/test-result@30.3.0': - dependencies: - '@jest/console': 30.3.0 - '@jest/types': 30.3.0 - '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.3 - - '@jest/test-sequencer@30.3.0': - dependencies: - '@jest/test-result': 30.3.0 - graceful-fs: 4.2.11 - jest-haste-map: 30.3.0 - slash: 3.0.0 - - '@jest/transform@30.3.0': - dependencies: - '@babel/core': 7.29.0 - '@jest/types': 30.3.0 - '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 7.0.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 30.3.0 - jest-regex-util: 30.0.1 - jest-util: 30.3.0 - pirates: 4.0.7 - slash: 3.0.0 - write-file-atomic: 5.0.1 - transitivePeerDependencies: - - supports-color - - '@jest/types@30.3.0': - dependencies: - '@jest/pattern': 30.0.1 - '@jest/schemas': 30.0.5 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.0 - '@types/yargs': 17.0.35 - chalk: 4.1.2 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@jsdevtools/ono@7.1.3': {} - - '@mongodb-js/saslprep@1.4.6': - dependencies: - sparse-bitfield: 3.0.3 - - '@napi-rs/wasm-runtime@0.2.12': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.2.9': {} - - '@scarf/scarf@1.4.0': - requiresBuild: true - - '@sinclair/typebox@0.34.49': {} - - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 - - '@sinonjs/fake-timers@15.1.1': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@tsconfig/node10@1.0.12': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} - - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/body-parser@1.19.6': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 25.5.0 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 25.5.0 - - '@types/cors@2.8.19': - dependencies: - '@types/node': 25.5.0 - - '@types/express-serve-static-core@5.1.1': - dependencies: - '@types/node': 25.5.0 - '@types/qs': 6.15.0 - '@types/range-parser': 1.2.7 - '@types/send': 1.2.1 - - '@types/express@5.0.6': - dependencies: - '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.1 - '@types/serve-static': 2.2.0 - - '@types/http-errors@2.0.5': {} - - '@types/istanbul-lib-coverage@2.0.6': {} - - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 - - '@types/jest@30.0.0': - dependencies: - expect: 30.3.0 - pretty-format: 30.3.0 - - '@types/json-schema@7.0.15': {} - - '@types/jsonwebtoken@9.0.10': - dependencies: - '@types/ms': 2.1.0 - '@types/node': 25.5.0 - - '@types/ms@2.1.0': {} - - '@types/node@25.5.0': - dependencies: - undici-types: 7.18.2 - - '@types/pg@8.20.0': - dependencies: - '@types/node': 25.5.0 - pg-protocol: 1.13.0 - pg-types: 2.2.0 - - '@types/qs@6.15.0': {} - - '@types/range-parser@1.2.7': {} - - '@types/send@1.2.1': - dependencies: - '@types/node': 25.5.0 - - '@types/serve-static@2.2.0': - dependencies: - '@types/http-errors': 2.0.5 - '@types/node': 25.5.0 - - '@types/stack-utils@2.0.3': {} - - '@types/strip-bom@3.0.0': {} - - '@types/strip-json-comments@0.0.30': {} - - '@types/swagger-jsdoc@6.0.4': {} - - '@types/swagger-ui-express@4.1.8': - dependencies: - '@types/express': 5.0.6 - '@types/serve-static': 2.2.0 - - '@types/webidl-conversions@7.0.3': {} - - '@types/whatwg-url@13.0.0': - dependencies: - '@types/webidl-conversions': 7.0.3 - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.35': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@ungap/structured-clone@1.3.0': {} - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - optional: true - - '@unrs/resolver-binding-android-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - dependencies: - '@napi-rs/wasm-runtime': 0.2.12 - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - optional: true - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - - acorn-walk@8.3.5: - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - ansi-styles@6.2.3: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - - arg@4.1.3: {} - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - babel-jest@30.3.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@jest/transform': 30.3.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.3.0(@babel/core@7.29.0) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-istanbul@7.0.1: - dependencies: - '@babel/helper-plugin-utils': 7.28.6 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 6.0.3 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-jest-hoist@30.3.0: - dependencies: - '@types/babel__core': 7.20.5 - - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) - - babel-preset-jest@30.3.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - babel-plugin-jest-hoist: 30.3.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) - - balanced-match@1.0.2: {} - - baseline-browser-mapping@2.10.12: {} - - bcryptjs@3.0.3: {} - - binary-extensions@2.3.0: {} - - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.0 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.3: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.12 - caniuse-lite: 1.0.30001781 - electron-to-chromium: 1.5.328 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - bs-logger@0.2.6: - dependencies: - fast-json-stable-stringify: 2.1.0 - - bser@2.1.1: - dependencies: - node-int64: 0.4.0 - - bson@7.2.0: {} - - buffer-equal-constant-time@1.0.1: {} - - buffer-from@1.1.2: {} - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - call-me-maybe@1.0.2: {} - - callsites@3.1.0: {} - - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001781: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - char-regex@1.0.2: {} - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - ci-info@4.4.0: {} - - cjs-module-lexer@2.2.0: {} - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - co@4.6.0: {} - - collect-v8-coverage@1.0.3: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - commander@6.2.0: {} - - commander@9.5.0: - optional: true - - concat-map@0.0.1: {} - - content-disposition@1.0.1: {} - - content-type@1.0.5: {} - - convert-source-map@2.0.0: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - create-require@1.1.1: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - dedent@1.7.2: {} - - deepmerge@4.3.1: {} - - depd@2.0.0: {} - - detect-newline@3.1.0: {} - - diff@4.0.4: {} - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dotenv@17.3.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - dynamic-dedupe@0.3.0: - dependencies: - xtend: 4.0.2 - - eastasianwidth@0.2.0: {} - - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.328: {} - - emittery@0.13.1: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encodeurl@2.0.0: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@2.0.0: {} - - esprima@4.0.1: {} - - esutils@2.0.3: {} - - etag@1.8.1: {} - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - exit-x@0.2.2: {} - - expect@30.3.0: - dependencies: - '@jest/expect-utils': 30.3.0 - '@jest/get-type': 30.1.0 - jest-matcher-utils: 30.3.0 - jest-message-util: 30.3.0 - jest-mock: 30.3.0 - jest-util: 30.3.0 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.0.1 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - fast-json-stable-stringify@2.1.0: {} - - fb-watchman@2.0.2: - dependencies: - bser: 2.1.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - 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 - - get-package-type@0.1.0: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@6.0.1: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@7.1.6: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - handlebars@4.7.9: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - helmet@8.1.0: {} - - html-escaper@2.0.2: {} - - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - human-signals@2.1.0: {} - - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - - import-local@3.2.0: - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ipaddr.js@1.9.1: {} - - is-arrayish@0.2.1: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-generator-fn@2.1.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-promise@4.0.0: {} - - is-stream@2.0.1: {} - - isexe@2.0.0: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-instrument@6.0.3: - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 7.7.4 - transitivePeerDependencies: - - supports-color - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-lib-source-maps@5.0.6: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - transitivePeerDependencies: - - supports-color - - istanbul-reports@3.2.0: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - jest-changed-files@30.3.0: - dependencies: - execa: 5.1.1 - jest-util: 30.3.0 - p-limit: 3.1.0 - - jest-circus@30.3.0: - dependencies: - '@jest/environment': 30.3.0 - '@jest/expect': 30.3.0 - '@jest/test-result': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.7.2 - is-generator-fn: 2.1.0 - jest-each: 30.3.0 - jest-matcher-utils: 30.3.0 - jest-message-util: 30.3.0 - jest-runtime: 30.3.0 - jest-snapshot: 30.3.0 - jest-util: 30.3.0 - p-limit: 3.1.0 - pretty-format: 30.3.0 - pure-rand: 7.0.1 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-cli@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): - dependencies: - '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - '@jest/test-result': 30.3.0 - '@jest/types': 30.3.0 - chalk: 4.1.2 - exit-x: 0.2.2 - import-local: 3.2.0 - jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - jest-util: 30.3.0 - jest-validate: 30.3.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - - jest-config@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): - dependencies: - '@babel/core': 7.29.0 - '@jest/get-type': 30.1.0 - '@jest/pattern': 30.0.1 - '@jest/test-sequencer': 30.3.0 - '@jest/types': 30.3.0 - babel-jest: 30.3.0(@babel/core@7.29.0) - chalk: 4.1.2 - ci-info: 4.4.0 - deepmerge: 4.3.1 - glob: 10.5.0 - graceful-fs: 4.2.11 - jest-circus: 30.3.0 - jest-docblock: 30.2.0 - jest-environment-node: 30.3.0 - jest-regex-util: 30.0.1 - jest-resolve: 30.3.0 - jest-runner: 30.3.0 - jest-util: 30.3.0 - jest-validate: 30.3.0 - parse-json: 5.2.0 - pretty-format: 30.3.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 25.5.0 - ts-node: 10.9.2(@types/node@25.5.0)(typescript@6.0.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-diff@30.3.0: - dependencies: - '@jest/diff-sequences': 30.3.0 - '@jest/get-type': 30.1.0 - chalk: 4.1.2 - pretty-format: 30.3.0 - - jest-docblock@30.2.0: - dependencies: - detect-newline: 3.1.0 - - jest-each@30.3.0: - dependencies: - '@jest/get-type': 30.1.0 - '@jest/types': 30.3.0 - chalk: 4.1.2 - jest-util: 30.3.0 - pretty-format: 30.3.0 - - jest-environment-node@30.3.0: - dependencies: - '@jest/environment': 30.3.0 - '@jest/fake-timers': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - jest-mock: 30.3.0 - jest-util: 30.3.0 - jest-validate: 30.3.0 - - jest-haste-map@30.3.0: - dependencies: - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 30.0.1 - jest-util: 30.3.0 - jest-worker: 30.3.0 - picomatch: 4.0.4 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - - jest-leak-detector@30.3.0: - dependencies: - '@jest/get-type': 30.1.0 - pretty-format: 30.3.0 - - jest-matcher-utils@30.3.0: - dependencies: - '@jest/get-type': 30.1.0 - chalk: 4.1.2 - jest-diff: 30.3.0 - pretty-format: 30.3.0 - - jest-message-util@30.3.0: - dependencies: - '@babel/code-frame': 7.29.0 - '@jest/types': 30.3.0 - '@types/stack-utils': 2.0.3 - chalk: 4.1.2 - graceful-fs: 4.2.11 - picomatch: 4.0.4 - pretty-format: 30.3.0 - slash: 3.0.0 - stack-utils: 2.0.6 - - jest-mock@30.3.0: - dependencies: - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - jest-util: 30.3.0 - - jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): - optionalDependencies: - jest-resolve: 30.3.0 - - jest-regex-util@30.0.1: {} - - jest-resolve-dependencies@30.3.0: - dependencies: - jest-regex-util: 30.0.1 - jest-snapshot: 30.3.0 - transitivePeerDependencies: - - supports-color - - jest-resolve@30.3.0: - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 30.3.0 - jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) - jest-util: 30.3.0 - jest-validate: 30.3.0 - slash: 3.0.0 - unrs-resolver: 1.11.1 - - jest-runner@30.3.0: - dependencies: - '@jest/console': 30.3.0 - '@jest/environment': 30.3.0 - '@jest/test-result': 30.3.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - chalk: 4.1.2 - emittery: 0.13.1 - exit-x: 0.2.2 - graceful-fs: 4.2.11 - jest-docblock: 30.2.0 - jest-environment-node: 30.3.0 - jest-haste-map: 30.3.0 - jest-leak-detector: 30.3.0 - jest-message-util: 30.3.0 - jest-resolve: 30.3.0 - jest-runtime: 30.3.0 - jest-util: 30.3.0 - jest-watcher: 30.3.0 - jest-worker: 30.3.0 - p-limit: 3.1.0 - source-map-support: 0.5.13 - transitivePeerDependencies: - - supports-color - - jest-runtime@30.3.0: - dependencies: - '@jest/environment': 30.3.0 - '@jest/fake-timers': 30.3.0 - '@jest/globals': 30.3.0 - '@jest/source-map': 30.0.1 - '@jest/test-result': 30.3.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - chalk: 4.1.2 - cjs-module-lexer: 2.2.0 - collect-v8-coverage: 1.0.3 - glob: 10.5.0 - graceful-fs: 4.2.11 - jest-haste-map: 30.3.0 - jest-message-util: 30.3.0 - jest-mock: 30.3.0 - jest-regex-util: 30.0.1 - jest-resolve: 30.3.0 - jest-snapshot: 30.3.0 - jest-util: 30.3.0 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - - jest-snapshot@30.3.0: - dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 - '@jest/expect-utils': 30.3.0 - '@jest/get-type': 30.1.0 - '@jest/snapshot-utils': 30.3.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) - chalk: 4.1.2 - expect: 30.3.0 - graceful-fs: 4.2.11 - jest-diff: 30.3.0 - jest-matcher-utils: 30.3.0 - jest-message-util: 30.3.0 - jest-util: 30.3.0 - pretty-format: 30.3.0 - semver: 7.7.4 - synckit: 0.11.12 - transitivePeerDependencies: - - supports-color - - jest-util@30.3.0: - dependencies: - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - chalk: 4.1.2 - ci-info: 4.4.0 - graceful-fs: 4.2.11 - picomatch: 4.0.4 - - jest-validate@30.3.0: - dependencies: - '@jest/get-type': 30.1.0 - '@jest/types': 30.3.0 - camelcase: 6.3.0 - chalk: 4.1.2 - leven: 3.1.0 - pretty-format: 30.3.0 - - jest-watcher@30.3.0: - dependencies: - '@jest/test-result': 30.3.0 - '@jest/types': 30.3.0 - '@types/node': 25.5.0 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 30.3.0 - string-length: 4.0.2 - - jest-worker@30.3.0: - dependencies: - '@types/node': 25.5.0 - '@ungap/structured-clone': 1.3.0 - jest-util: 30.3.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): - dependencies: - '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - '@jest/types': 30.3.0 - import-local: 3.2.0 - jest-cli: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - - js-tokens@4.0.0: {} - - js-yaml@3.14.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} - - json-parse-even-better-errors@2.3.1: {} - - json5@2.2.3: {} - - jsonwebtoken@9.0.3: - dependencies: - jws: 4.0.1 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.7.4 - - jwa@2.0.1: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@4.0.1: - dependencies: - jwa: 2.0.1 - safe-buffer: 5.2.1 - - kareem@3.2.0: {} - - leven@3.1.0: {} - - lines-and-columns@1.2.4: {} - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - lodash.get@4.4.2: {} - - lodash.includes@4.3.0: {} - - lodash.isboolean@3.0.3: {} - - lodash.isequal@4.5.0: {} - - lodash.isinteger@4.0.4: {} - - lodash.isnumber@3.0.3: {} - - lodash.isplainobject@4.0.6: {} - - lodash.isstring@4.0.1: {} - - lodash.memoize@4.1.2: {} - - lodash.mergewith@4.6.2: {} - - lodash.once@4.1.1: {} - - lru-cache@10.4.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - make-dir@4.0.0: - dependencies: - semver: 7.7.4 - - make-error@1.3.6: {} - - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - - math-intrinsics@1.1.0: {} - - media-typer@1.1.0: {} - - memory-pager@1.5.0: {} - - merge-descriptors@2.0.0: {} - - merge-stream@2.0.0: {} - - mime-db@1.54.0: {} - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - mimic-fn@2.1.0: {} - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.9: - dependencies: - brace-expansion: 2.0.3 - - minimist@1.2.8: {} - - minipass@7.1.3: {} - - mkdirp@1.0.4: {} - - mongodb-connection-string-url@7.0.1: - dependencies: - '@types/whatwg-url': 13.0.0 - whatwg-url: 14.2.0 - - mongodb@7.1.1: - dependencies: - '@mongodb-js/saslprep': 1.4.6 - bson: 7.2.0 - mongodb-connection-string-url: 7.0.1 - - mongoose@9.3.2: - dependencies: - kareem: 3.2.0 - mongodb: 7.1.1 - mpath: 0.9.0 - mquery: 6.0.0 - ms: 2.1.3 - sift: 17.1.3 - transitivePeerDependencies: - - '@aws-sdk/credential-providers' - - '@mongodb-js/zstd' - - gcp-metadata - - kerberos - - mongodb-client-encryption - - snappy - - socks - - mpath@0.9.0: {} - - mquery@6.0.0: {} - - ms@2.1.3: {} - - napi-postinstall@0.3.4: {} - - natural-compare@1.4.0: {} - - negotiator@1.0.0: {} - - neo-async@2.6.2: {} - - node-int64@0.4.0: {} - - node-releases@2.0.36: {} - - normalize-path@3.0.0: {} - - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - openapi-types@12.1.3: {} - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.29.0 - error-ex: 1.3.4 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parseurl@1.3.3: {} - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - - path-to-regexp@8.3.0: {} - - pg-cloudflare@1.3.0: - optional: true - - pg-connection-string@2.12.0: {} - - pg-int8@1.0.1: {} - - pg-pool@3.13.0(pg@8.20.0): - dependencies: - pg: 8.20.0 - - pg-protocol@1.13.0: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.1 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - pg@8.20.0: - dependencies: - pg-connection-string: 2.12.0 - pg-pool: 3.13.0(pg@8.20.0) - pg-protocol: 1.13.0 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.3.0 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - pirates@4.0.7: {} - - pkg-dir@4.2.0: - dependencies: - find-up: 4.1.0 - - postgres-array@2.0.0: {} - - postgres-bytea@1.0.1: {} - - postgres-date@1.0.7: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - - pretty-format@30.3.0: - dependencies: - '@jest/schemas': 30.0.5 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - punycode@2.3.1: {} - - pure-rand@7.0.1: {} - - qs@6.15.0: - dependencies: - side-channel: 1.1.0 - - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - - react-is@18.3.1: {} - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.2 - - require-directory@2.1.1: {} - - resolve-cwd@3.0.0: - dependencies: - resolve-from: 5.0.0 - - resolve-from@5.0.0: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - rimraf@2.7.1: - dependencies: - glob: 7.2.3 - - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.3.0 - transitivePeerDependencies: - - supports-color - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - semver@6.3.1: {} - - semver@7.7.4: {} - - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - setprototypeof@1.2.0: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - sift@17.1.3: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - source-map-support@0.5.13: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - sparse-bitfield@3.0.3: - dependencies: - memory-pager: 1.5.0 - - split2@4.2.0: {} - - sprintf-js@1.0.3: {} - - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 - - statuses@2.0.2: {} - - string-length@4.0.2: - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-bom@3.0.0: {} - - strip-bom@4.0.0: {} - - strip-final-newline@2.0.0: {} - - strip-json-comments@2.0.1: {} - - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - swagger-jsdoc@6.2.8(openapi-types@12.1.3): - dependencies: - commander: 6.2.0 - doctrine: 3.0.0 - glob: 7.1.6 - lodash.mergewith: 4.6.2 - swagger-parser: 10.0.3(openapi-types@12.1.3) - yaml: 2.0.0-1 - transitivePeerDependencies: - - openapi-types - - swagger-parser@10.0.3(openapi-types@12.1.3): - dependencies: - '@apidevtools/swagger-parser': 10.0.3(openapi-types@12.1.3) - transitivePeerDependencies: - - openapi-types - - swagger-ui-dist@5.32.1: - dependencies: - '@scarf/scarf': 1.4.0 - - swagger-ui-express@5.0.1(express@5.2.1): - dependencies: - express: 5.2.1 - swagger-ui-dist: 5.32.1 - - synckit@0.11.12: - dependencies: - '@pkgr/core': 0.2.9 - - test-exclude@6.0.0: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.5 - - tmpl@1.0.5: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} - - tr46@5.1.1: - dependencies: - punycode: 2.3.1 - - tree-kill@1.2.2: {} - - ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)))(typescript@6.0.2): - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - handlebars: 4.7.9 - jest: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.4 - type-fest: 4.41.0 - typescript: 6.0.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.29.0 - '@jest/transform': 30.3.0 - '@jest/types': 30.3.0 - babel-jest: 30.3.0(@babel/core@7.29.0) - jest-util: 30.3.0 - - ts-node-dev@2.0.0(@types/node@25.5.0)(typescript@6.0.2): - dependencies: - chokidar: 3.6.0 - dynamic-dedupe: 0.3.0 - minimist: 1.2.8 - mkdirp: 1.0.4 - resolve: 1.22.11 - rimraf: 2.7.1 - source-map-support: 0.5.21 - tree-kill: 1.2.2 - ts-node: 10.9.2(@types/node@25.5.0)(typescript@6.0.2) - tsconfig: 7.0.0 - typescript: 6.0.2 - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 25.5.0 - acorn: 8.16.0 - acorn-walk: 8.3.5 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.4 - make-error: 1.3.6 - typescript: 6.0.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - tsconfig@7.0.0: - dependencies: - '@types/strip-bom': 3.0.0 - '@types/strip-json-comments': 0.0.30 - strip-bom: 3.0.0 - strip-json-comments: 2.0.1 - - tslib@2.8.1: - optional: true - - type-detect@4.0.8: {} - - type-fest@0.21.3: {} - - type-fest@4.41.0: {} - - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - - typescript@6.0.2: {} - - uglify-js@3.19.3: - optional: true - - undici-types@7.18.2: {} - - unpipe@1.0.0: {} - - unrs-resolver@1.11.1: - dependencies: - napi-postinstall: 0.3.4 - optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.11.1 - '@unrs/resolver-binding-android-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-x64': 1.11.1 - '@unrs/resolver-binding-freebsd-x64': 1.11.1 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 - '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-musl': 1.11.1 - '@unrs/resolver-binding-wasm32-wasi': 1.11.1 - '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 - '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 - '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - requiresBuild: true - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - v8-compile-cache-lib@3.0.1: {} - - v8-to-istanbul@9.3.0: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - '@types/istanbul-lib-coverage': 2.0.6 - convert-source-map: 2.0.0 - - validator@13.15.26: {} - - vary@1.1.2: {} - - walker@1.0.8: - dependencies: - makeerror: 1.0.12 - - webidl-conversions@7.0.0: {} - - whatwg-url@14.2.0: - dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - wordwrap@1.0.0: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - - wrappy@1.0.2: {} - - write-file-atomic@5.0.1: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 4.1.0 - - xtend@4.0.2: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yaml@2.0.0-1: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yn@3.1.1: {} - - yocto-queue@0.1.0: {} - - z-schema@5.0.5: - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.15.26 - optionalDependencies: - commander: 9.5.0 +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + bcryptjs: + specifier: ^3.0.3 + version: 3.0.3 + cors: + specifier: ^2.8.6 + version: 2.8.6 + dotenv: + specifier: ^17.4.2 + version: 17.4.2 + express: + specifier: ^5.2.1 + version: 5.2.1 + helmet: + specifier: ^8.1.0 + version: 8.1.0 + jsonwebtoken: + specifier: ^9.0.3 + version: 9.0.3 + mongoose: + specifier: ^9.6.2 + version: 9.6.2 + swagger-jsdoc: + specifier: ^6.2.8 + version: 6.2.8(openapi-types@12.1.3) + swagger-ui-express: + specifier: ^5.0.1 + version: 5.0.1(express@5.2.1) + devDependencies: + '@types/cors': + specifier: ^2.8.19 + version: 2.8.19 + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 + '@types/jest': + specifier: ^30.0.0 + version: 30.0.0 + '@types/jsonwebtoken': + specifier: ^9.0.10 + version: 9.0.10 + '@types/node': + specifier: ^25.5.0 + version: 25.5.0 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.0 + '@types/swagger-jsdoc': + specifier: ^6.0.4 + version: 6.0.4 + '@types/swagger-ui-express': + specifier: ^4.1.8 + version: 4.1.8 + jest: + specifier: ^30.3.0 + version: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + pg: + specifier: ^8.20.0 + version: 8.20.0 + ts-jest: + specifier: ^29.4.6 + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)))(typescript@6.0.2) + ts-node-dev: + specifier: ^2.0.0 + version: 2.0.0(@types/node@25.5.0)(typescript@6.0.2) + typescript: + specifier: ^6.0.2 + version: 6.0.2 + +packages: + + '@apidevtools/json-schema-ref-parser@9.1.2': + resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==} + + '@apidevtools/openapi-schemas@2.1.0': + resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} + engines: {node: '>=10'} + + '@apidevtools/swagger-methods@3.0.2': + resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + + '@apidevtools/swagger-parser@10.0.3': + resolution: {integrity: sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==} + peerDependencies: + openapi-types: '>=7' + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@mongodb-js/saslprep@1.4.11': + resolution: {integrity: sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@scarf/scarf@1.4.0': + resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + + '@sinclair/typebox@0.34.49': + resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@15.1.1': + resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==} + + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/cors@2.8.19': + resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + + '@types/express-serve-static-core@5.1.1': + resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} + + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/jsonwebtoken@9.0.10': + resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} + + '@types/qs@6.15.0': + resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/strip-bom@3.0.0': + resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==} + + '@types/strip-json-comments@0.0.30': + resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==} + + '@types/swagger-jsdoc@6.0.4': + resolution: {integrity: sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==} + + '@types/swagger-ui-express@4.1.8': + resolution: {integrity: sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@13.0.0': + resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-0 + + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.10.12: + resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + bcryptjs@3.0.3: + resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + bson@7.2.0: + resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} + engines: {node: '>=20.19.0'} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001781: + resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@6.2.0: + resolution: {integrity: sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==} + engines: {node: '>= 6'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + dynamic-dedupe@0.3.0: + resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.328: + resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@10.5.0: + resolution: {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 + hasBin: true + + glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + 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 + + glob@7.2.3: + resolution: {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 + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + helmet@8.1.0: + resolution: {integrity: sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==} + engines: {node: '>=18.0.0'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@30.3.0: + resolution: {integrity: sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.3.0: + resolution: {integrity: sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + kareem@3.3.0: + resolution: {integrity: sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==} + engines: {node: '>=18.0.0'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mongodb-connection-string-url@7.0.1: + resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} + engines: {node: '>=20.19.0'} + + mongodb@7.2.0: + resolution: {integrity: sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.806.0 + '@mongodb-js/zstd': ^7.0.0 + gcp-metadata: ^7.0.1 + kerberos: ^7.0.0 + mongodb-client-encryption: '>=7.0.0 <7.1.0' + snappy: ^7.3.2 + socks: ^2.8.6 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose@9.6.2: + resolution: {integrity: sha512-7m8HntjkoRnwEmuPC0kdlwcZXJOQf4twumFj+PNzg/anqqZE2Er7hQslqyzy07mP3JcFjoTSgH5765PyqOXsxw==} + engines: {node: '>=20.19.0'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@6.0.0: + resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==} + engines: {node: '>=20.19.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} + + pg-connection-string@2.12.0: + resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.13.0: + resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + swagger-jsdoc@6.2.8: + resolution: {integrity: sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==} + engines: {node: '>=12.0.0'} + hasBin: true + + swagger-parser@10.0.3: + resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==} + engines: {node: '>=10'} + + swagger-ui-dist@5.32.1: + resolution: {integrity: sha512-6HQoo7+j8PA2QqP5kgAb9dl1uxUjvR0SAoL/WUp1sTEvm0F6D5npgU2OGCLwl++bIInqGlEUQ2mpuZRZYtyCzQ==} + + swagger-ui-express@5.0.1: + resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} + engines: {node: '>= v0.10.32'} + peerDependencies: + express: '>=4.0.0 || >=5.0.0-beta' + + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-jest@29.4.6: + resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + 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 + esbuild: '*' + 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 + + ts-node-dev@2.0.0: + resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} + engines: {node: '>=0.8.0'} + hasBin: true + peerDependencies: + node-notifier: '*' + typescript: '*' + peerDependenciesMeta: + node-notifier: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig@7.0.0: + resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + validator@13.15.26: + resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} + engines: {node: '>= 0.10'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.0.0-1: + resolution: {integrity: sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==} + engines: {node: '>= 6'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + z-schema@5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + +snapshots: + + '@apidevtools/json-schema-ref-parser@9.1.2': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + call-me-maybe: 1.0.2 + js-yaml: 4.1.1 + + '@apidevtools/openapi-schemas@2.1.0': {} + + '@apidevtools/swagger-methods@3.0.2': {} + + '@apidevtools/swagger-parser@10.0.3(openapi-types@12.1.3)': + dependencies: + '@apidevtools/json-schema-ref-parser': 9.1.2 + '@apidevtools/openapi-schemas': 2.1.0 + '@apidevtools/swagger-methods': 3.0.2 + '@jsdevtools/ono': 7.1.3 + call-me-maybe: 1.0.2 + openapi-types: 12.1.3 + z-schema: 5.0.5 + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@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.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + chalk: 4.1.2 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + + '@jest/core@30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2))': + dependencies: + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/diff-sequences@30.3.0': {} + + '@jest/environment@30.3.0': + dependencies: + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + jest-mock: 30.3.0 + + '@jest/expect-utils@30.3.0': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@30.3.0': + dependencies: + expect: 30.3.0 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.1.1 + '@types/node': 25.5.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@30.3.0': + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 25.5.0 + jest-regex-util: 30.0.1 + + '@jest/reporters@30.3.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 25.5.0 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit-x: 0.2.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 + slash: 3.0.0 + string-length: 4.0.2 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.49 + + '@jest/snapshot-utils@30.3.0': + dependencies: + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@30.3.0': + dependencies: + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3 + + '@jest/test-sequencer@30.3.0': + dependencies: + '@jest/test-result': 30.3.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + slash: 3.0.0 + + '@jest/transform@30.3.0': + dependencies: + '@babel/core': 7.29.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + + '@jest/types@30.3.0': + dependencies: + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.5 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.5.0 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsdevtools/ono@7.1.3': {} + + '@mongodb-js/saslprep@1.4.11': + dependencies: + sparse-bitfield: 3.0.3 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@scarf/scarf@1.4.0': {} + + '@sinclair/typebox@0.34.49': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@15.1.1': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@tsconfig/node10@1.0.12': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 25.5.0 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 25.5.0 + + '@types/cors@2.8.19': + dependencies: + '@types/node': 25.5.0 + + '@types/express-serve-static-core@5.1.1': + dependencies: + '@types/node': 25.5.0 + '@types/qs': 6.15.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + + '@types/express@5.0.6': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.1 + '@types/serve-static': 2.2.0 + + '@types/http-errors@2.0.5': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@30.0.0': + dependencies: + expect: 30.3.0 + pretty-format: 30.3.0 + + '@types/json-schema@7.0.15': {} + + '@types/jsonwebtoken@9.0.10': + dependencies: + '@types/ms': 2.1.0 + '@types/node': 25.5.0 + + '@types/ms@2.1.0': {} + + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + + '@types/pg@8.20.0': + dependencies: + '@types/node': 25.5.0 + pg-protocol: 1.13.0 + pg-types: 2.2.0 + + '@types/qs@6.15.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@1.2.1': + dependencies: + '@types/node': 25.5.0 + + '@types/serve-static@2.2.0': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 25.5.0 + + '@types/stack-utils@2.0.3': {} + + '@types/strip-bom@3.0.0': {} + + '@types/strip-json-comments@0.0.30': {} + + '@types/swagger-jsdoc@6.0.4': {} + + '@types/swagger-ui-express@4.1.8': + dependencies: + '@types/express': 5.0.6 + '@types/serve-static': 2.2.0 + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@13.0.0': + dependencies: + '@types/webidl-conversions': 7.0.3 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@ungap/structured-clone@1.3.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-walk@8.3.5: + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + babel-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.28.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@30.3.0: + dependencies: + '@types/babel__core': 7.20.5 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.10.12: {} + + bcryptjs@3.0.3: {} + + binary-extensions@2.3.0: {} + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.14: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.12 + caniuse-lite: 1.0.30001781 + electron-to-chromium: 1.5.328 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + bson@7.2.0: {} + + buffer-equal-constant-time@1.0.1: {} + + buffer-from@1.1.2: {} + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + call-me-maybe@1.0.2: {} + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001781: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@4.4.0: {} + + cjs-module-lexer@2.2.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + collect-v8-coverage@1.0.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@6.2.0: {} + + commander@9.5.0: + optional: true + + concat-map@0.0.1: {} + + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + dedent@1.7.2: {} + + deepmerge@4.3.1: {} + + depd@2.0.0: {} + + detect-newline@3.1.0: {} + + diff@4.0.4: {} + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dotenv@17.4.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + dynamic-dedupe@0.3.0: + dependencies: + xtend: 4.0.2 + + eastasianwidth@0.2.0: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.328: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@2.0.0: {} + + esprima@4.0.1: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit-x@0.2.2: {} + + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-json-stable-stringify@2.1.0: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + 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 + + get-package-type@0.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.1.6: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + helmet@8.1.0: {} + + html-escaper@2.0.2: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + human-signals@2.1.0: {} + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-promise@4.0.0: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-changed-files@30.3.0: + dependencies: + execa: 5.1.1 + jest-util: 30.3.0 + p-limit: 3.1.0 + + jest-circus@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + p-limit: 3.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): + dependencies: + '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + exit-x: 0.2.2 + import-local: 3.2.0 + jest-config: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + jest-util: 30.3.0 + jest-validate: 30.3.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jest-config@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + parse-json: 5.2.0 + pretty-format: 30.3.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 25.5.0 + ts-node: 10.9.2(@types/node@25.5.0)(typescript@6.0.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@30.2.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + jest-util: 30.3.0 + pretty-format: 30.3.0 + + jest-environment-node@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + + jest-haste-map@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.4 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 + + jest-matcher-utils@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.3.0 + pretty-format: 30.3.0 + + jest-message-util@30.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + jest-util: 30.3.0 + + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 + + jest-regex-util@30.0.1: {} + + jest-resolve-dependencies@30.3.0: + dependencies: + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@30.3.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 + slash: 3.0.0 + unrs-resolver: 1.11.1 + + jest-runner@30.3.0: + dependencies: + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + chalk: 4.1.2 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@30.3.0: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + chalk: 4.1.2 + expect: 30.3.0 + graceful-fs: 4.2.11 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 + semver: 7.7.4 + synckit: 0.11.12 + transitivePeerDependencies: + - supports-color + + jest-util@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-validate@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.3.0 + + jest-watcher@30.3.0: + dependencies: + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.5.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.3.0 + string-length: 4.0.2 + + jest-worker@30.3.0: + dependencies: + '@types/node': 25.5.0 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.3.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)): + dependencies: + '@jest/core': 30.3.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + '@jest/types': 30.3.0 + import-local: 3.2.0 + jest-cli: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + jsonwebtoken@9.0.3: + dependencies: + jws: 4.0.1 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.7.4 + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + kareem@3.3.0: {} + + leven@3.1.0: {} + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.get@4.4.2: {} + + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isequal@4.5.0: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + + lodash.memoize@4.1.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.once@4.1.1: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + memory-pager@1.5.0: {} + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mimic-fn@2.1.0: {} + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.14 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + mkdirp@1.0.4: {} + + mongodb-connection-string-url@7.0.1: + dependencies: + '@types/whatwg-url': 13.0.0 + whatwg-url: 14.2.0 + + mongodb@7.2.0: + dependencies: + '@mongodb-js/saslprep': 1.4.11 + bson: 7.2.0 + mongodb-connection-string-url: 7.0.1 + + mongoose@9.6.2: + dependencies: + kareem: 3.3.0 + mongodb: 7.2.0 + mpath: 0.9.0 + mquery: 6.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + + mpath@0.9.0: {} + + mquery@6.0.0: {} + + ms@2.1.3: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + neo-async@2.6.2: {} + + node-int64@0.4.0: {} + + node-releases@2.0.36: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + openapi-types@12.1.3: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-to-regexp@8.4.2: {} + + pg-cloudflare@1.3.0: + optional: true + + pg-connection-string@2.12.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.13.0(pg@8.20.0): + dependencies: + pg: 8.20.0 + + pg-protocol@1.13.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.20.0: + dependencies: + pg-connection-string: 2.12.0 + pg-pool: 3.13.0(pg@8.20.0) + pg-protocol: 1.13.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.3.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + pretty-format@30.3.0: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + pure-rand@7.0.1: {} + + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + react-is@18.3.1: {} + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + require-directory@2.1.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sift@17.1.3: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + statuses@2.0.2: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + swagger-jsdoc@6.2.8(openapi-types@12.1.3): + dependencies: + commander: 6.2.0 + doctrine: 3.0.0 + glob: 7.1.6 + lodash.mergewith: 4.6.2 + swagger-parser: 10.0.3(openapi-types@12.1.3) + yaml: 2.0.0-1 + transitivePeerDependencies: + - openapi-types + + swagger-parser@10.0.3(openapi-types@12.1.3): + dependencies: + '@apidevtools/swagger-parser': 10.0.3(openapi-types@12.1.3) + transitivePeerDependencies: + - openapi-types + + swagger-ui-dist@5.32.1: + dependencies: + '@scarf/scarf': 1.4.0 + + swagger-ui-express@5.0.1(express@5.2.1): + dependencies: + express: 5.2.1 + swagger-ui-dist: 5.32.1 + + synckit@0.11.12: + dependencies: + '@pkgr/core': 0.2.9 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.5 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)))(typescript@6.0.2): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.9 + jest: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.4 + type-fest: 4.41.0 + typescript: 6.0.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + jest-util: 30.3.0 + + ts-node-dev@2.0.0(@types/node@25.5.0)(typescript@6.0.2): + dependencies: + chokidar: 3.6.0 + dynamic-dedupe: 0.3.0 + minimist: 1.2.8 + mkdirp: 1.0.4 + resolve: 1.22.11 + rimraf: 2.7.1 + source-map-support: 0.5.21 + tree-kill: 1.2.2 + ts-node: 10.9.2(@types/node@25.5.0)(typescript@6.0.2) + tsconfig: 7.0.0 + typescript: 6.0.2 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + + ts-node@10.9.2(@types/node@25.5.0)(typescript@6.0.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 25.5.0 + acorn: 8.16.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 6.0.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsconfig@7.0.0: + dependencies: + '@types/strip-bom': 3.0.0 + '@types/strip-json-comments': 0.0.30 + strip-bom: 3.0.0 + strip-json-comments: 2.0.1 + + tslib@2.8.1: + optional: true + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@4.41.0: {} + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typescript@6.0.2: {} + + uglify-js@3.19.3: + optional: true + + undici-types@7.18.2: {} + + unpipe@1.0.0: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + validator@13.15.26: {} + + vary@1.1.2: {} + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wordwrap@1.0.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + xtend@4.0.2: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.0.0-1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + z-schema@5.0.5: + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.15.26 + optionalDependencies: + commander: 9.5.0 diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetCatalogQueryHandler.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetCatalogQueryHandler.cs index 796a8f6..e0463a0 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetCatalogQueryHandler.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetCatalogQueryHandler.cs @@ -3,42 +3,143 @@ using TuColmadoRD.Core.Application.Interfaces.Tenancy; using TuColmadoRD.Core.Application.Inventory.Queries; using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; using TuColmadoRD.Core.Domain.ValueObjects.Base; using TuColmadoRD.Infrastructure.Persistence.Contexts; namespace TuColmadoRD.Presentation.API.Endpoints.Inventory.Handlers; -internal sealed class GetCatalogQueryHandler : IRequestHandler, DomainError>> +internal sealed class GetCatalogQueryHandler + : IRequestHandler, DomainError>> { + private static readonly Dictionary UnitLabels = new() + { + { 1, "Libra" }, + { 2, "Onza" }, + { 3, "Kilogramo"}, + { 10, "Unidad" }, + { 11, "Caja" }, + { 12, "Paquete" }, + { 13, "Saco" }, + { 20, "Litro" }, + { 21, "Galón" }, + { 22, "Botella" }, + }; + private readonly TuColmadoDbContext _dbContext; private readonly ITenantProvider _tenantProvider; public GetCatalogQueryHandler(TuColmadoDbContext dbContext, ITenantProvider tenantProvider) { - _dbContext = dbContext; - _tenantProvider = tenantProvider; + _dbContext = dbContext; + _tenantProvider = tenantProvider; } - public async Task, DomainError>> Handle(GetCatalogQuery request, CancellationToken cancellationToken) + public async Task, DomainError>> Handle( + GetCatalogQuery request, CancellationToken cancellationToken) { var tenantId = (Guid)_tenantProvider.TenantId; + // 1. Active products + category names var products = await (from p in _dbContext.Products join c in _dbContext.Categories on p.CategoryId equals c.Id where p.TenantId.Value == tenantId && p.IsActive - select new CatalogItemDto( + orderby p.Name + select new + { p.Id, p.Name, p.CategoryId, - c.Name, - p.SalePrice.Amount, - p.StockQuantity, - p.ItbisRate.Rate, - p.UnitType.Id, - p.IsActive)) + CategoryName = c.Name, + ItbisRate = p.ItbisRate.Rate, + }) + .AsNoTracking() + .ToListAsync(cancellationToken); + + if (products.Count == 0) + return OperationResult, DomainError>.Good( + Array.Empty()); + + var productIds = products.Select(p => p.Id).ToList(); + + // 2. Active presentations for those products + var presentations = await _dbContext.ProductPresentations + .Where(pp => productIds.Contains(pp.ProductId) + && pp.TenantId.Value == tenantId + && pp.IsActive) + .AsNoTracking() + .ToListAsync(cancellationToken); + + var presentationIds = presentations.Select(pp => pp.Id).ToList(); + + // 3. Packaged stock counters + var packagedStocks = await _dbContext.PackagedStocks + .Where(ps => presentationIds.Contains(ps.PresentationId) + && ps.TenantId.Value == tenantId) + .AsNoTracking() + .Select(ps => new { ps.PresentationId, ps.Quantity }) + .ToDictionaryAsync(ps => ps.PresentationId, ps => ps.Quantity, cancellationToken); + + // 4. Container stats — load all, filter empty in memory (ContainerStatus.Empty.Id == 3) + var containers = await _dbContext.StockContainers + .Where(sc => presentationIds.Contains(sc.PresentationId) + && sc.TenantId.Value == tenantId) .AsNoTracking() + .Select(sc => new { sc.PresentationId, sc.Status, sc.CurrentRemaining }) .ToListAsync(cancellationToken); - return OperationResult, DomainError>.Good(products); + var containerStats = containers + .Where(sc => sc.Status != ContainerStatus.Empty) + .GroupBy(sc => sc.PresentationId) + .ToDictionary( + g => g.Key, + g => (Count: g.Count(), Remaining: (int)g.Sum(x => x.CurrentRemaining))); + + // 5. Build catalog grouped by product + var presentationsByProduct = presentations + .GroupBy(pp => pp.ProductId) + .ToDictionary(g => g.Key, g => g.ToList()); + + var catalog = products.Select(p => + { + var pres = presentationsByProduct.TryGetValue(p.Id, out var list) + ? list + : []; + + var presDtos = pres.Select(pp => + { + var pkgQty = packagedStocks.TryGetValue(pp.Id, out var q) ? q : 0; + containerStats.TryGetValue(pp.Id, out var cs); + + var isPackaged = pp.PresentationType.Id == PresentationType.PackagedUnit.Id; + var stockQty = isPackaged ? pkgQty : cs.Remaining; + var unitId = (int)pp.MeasureUnit; + + return new CatalogPresentationDto( + pp.Id, + pp.ProductId, + pp.DisplayName, + pp.PresentationType.Id, + pp.PresentationType.Name, + pp.SellMode.Id, + pp.SellMode.Name, + pp.Brand, + pp.NominalCapacity, + unitId, + UnitLabels.TryGetValue(unitId, out var label) ? label : pp.MeasureUnit.ToString(), + pp.SalePrice.Amount, + pp.CostPrice.Amount, + pp.IsActive, + stockQty, + cs.Count, + pkgQty); + }).ToList(); + + return new CatalogItemDto( + p.Id, p.Name, p.CategoryId, p.CategoryName, p.ItbisRate, true, + presDtos.AsReadOnly()); + }).ToList(); + + return OperationResult, DomainError>.Good(catalog); } } diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetFundTransactionsQueryHandler.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetFundTransactionsQueryHandler.cs new file mode 100644 index 0000000..c034d65 --- /dev/null +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetFundTransactionsQueryHandler.cs @@ -0,0 +1,67 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Presentation.API.Endpoints.Inventory.Handlers; + +internal sealed class GetFundTransactionsQueryHandler + : IRequestHandler> +{ + private readonly TuColmadoDbContext _dbContext; + private readonly ITenantProvider _tenantProvider; + + public GetFundTransactionsQueryHandler(TuColmadoDbContext dbContext, ITenantProvider tenantProvider) + { + _dbContext = dbContext; + _tenantProvider = tenantProvider; + } + + public async Task> Handle( + GetFundTransactionsQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var page = Math.Max(1, request.Page); + var pageSize = Math.Clamp(request.PageSize, 1, 100); + + var fundExists = await _dbContext.MonetaryFunds + .AnyAsync(f => f.Id == request.FundId && f.TenantId.Value == tenantId, cancellationToken); + + if (!fundExists) + return OperationResult.Bad( + DomainError.NotFound("fund.not_found")); + + var baseQuery = _dbContext.FundTransactions + .Where(t => t.FundId == request.FundId && t.TenantId.Value == tenantId) + .AsNoTracking(); + + var totalCount = await baseQuery.CountAsync(cancellationToken); + var totalPages = (int)Math.Ceiling((double)totalCount / pageSize); + + var items = await baseQuery + .OrderByDescending(t => t.OccurredAt) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + var dtos = items.Select(t => new FundTransactionPagedDto( + t.Id, + t.FundId, + t.Type.Id, + t.Type.Name, + t.Amount.Amount, + t.Category?.Id, + t.Category?.Name, + t.Description, + t.JustificationNote, + t.ReferenceId, + t.BalanceAfter.Amount, + t.OccurredAt)).ToList(); + + var result = new FundTransactionsPagedResult(dtos, page, pageSize, totalCount, totalPages); + return OperationResult.Good(result); + } +} diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetLowStockQueryHandler.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetLowStockQueryHandler.cs index 9922853..79f5704 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetLowStockQueryHandler.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetLowStockQueryHandler.cs @@ -26,18 +26,22 @@ public async Task> Handle( var tenantId = (Guid)_tenantProvider.TenantId; var threshold = Math.Max(0, request.Threshold); - var items = await _dbContext.Set() + var items = await (from ps in _dbContext.PackagedStocks + join pp in _dbContext.ProductPresentations on ps.PresentationId equals pp.Id + join p in _dbContext.Products on pp.ProductId equals p.Id + where ps.TenantId.Value == tenantId + && pp.IsActive + && p.IsActive + && ps.Quantity <= threshold + orderby ps.Quantity + select new LowStockItemDto( + ps.PresentationId, + p.Id, + p.Name, + pp.DisplayName, + ps.Quantity, + threshold)) .AsNoTracking() - .Where(p => - p.TenantId.Value == tenantId && - p.IsActive && - p.StockQuantity <= threshold) - .OrderBy(p => p.StockQuantity) - .Select(p => new LowStockItemDto( - p.Id, - p.Name, - p.StockQuantity, - threshold)) .ToListAsync(cancellationToken); var response = new LowStockResponse(items.Count, items.AsReadOnly()); diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetStockEntriesQueryHandler.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetStockEntriesQueryHandler.cs new file mode 100644 index 0000000..8c099a6 --- /dev/null +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/GetStockEntriesQueryHandler.cs @@ -0,0 +1,83 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Presentation.API.Endpoints.Inventory.Handlers; + +internal sealed class GetStockEntriesQueryHandler + : IRequestHandler> +{ + private readonly TuColmadoDbContext _dbContext; + private readonly ITenantProvider _tenantProvider; + + public GetStockEntriesQueryHandler(TuColmadoDbContext dbContext, ITenantProvider tenantProvider) + { + _dbContext = dbContext; + _tenantProvider = tenantProvider; + } + + public async Task> Handle( + GetStockEntriesQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var page = Math.Max(1, request.Page); + var pageSize = Math.Clamp(request.PageSize, 1, 100); + + var baseQuery = _dbContext.StockEntries + .Where(e => e.TenantId.Value == tenantId) + .AsNoTracking(); + + var totalCount = await baseQuery.CountAsync(cancellationToken); + var totalPages = (int)Math.Ceiling((double)totalCount / pageSize); + + var entries = await baseQuery + .OrderByDescending(e => e.PurchasedAt) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + if (entries.Count == 0) + { + var empty = new StockEntriesPagedResult([], totalCount, totalPages); + return OperationResult.Good(empty); + } + + var entryIds = entries.Select(e => e.Id).ToList(); + + // Load lines with presentation display names via join + var lines = await (from l in _dbContext.StockEntryLines + join pp in _dbContext.ProductPresentations on l.PresentationId equals pp.Id + where entryIds.Contains(l.StockEntryId) + select new StockEntryLineResultDto( + l.Id, + l.StockEntryId, + l.PresentationId, + pp.DisplayName, + l.ContainerCount, + l.UnitsPerContainer, + l.NominalSizePerUnit, + l.CostPerUnit.Amount, + l.CostPerUnit.Amount * l.ContainerCount * l.UnitsPerContainer)) + .AsNoTracking() + .ToListAsync(cancellationToken); + + var linesByEntry = lines.GroupBy(l => l.StockEntryId) + .ToDictionary(g => g.Key, g => (IReadOnlyList)g.ToList()); + + var dtos = entries.Select(e => new StockEntryResultDto( + e.Id, + e.PurchasedAt, + e.TotalCost.Amount, + string.IsNullOrEmpty(e.SupplierName) ? null : e.SupplierName, + string.IsNullOrEmpty(e.Notes) ? null : e.Notes, + e.FundTransactionId, + linesByEntry.TryGetValue(e.Id, out var ls) ? ls : [])).ToList(); + + var result = new StockEntriesPagedResult(dtos, totalCount, totalPages); + return OperationResult.Good(result); + } +} diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryContracts.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryContracts.cs index 0ba57ad..9858b39 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryContracts.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryContracts.cs @@ -1,37 +1,64 @@ namespace TuColmadoRD.Presentation.API.Endpoints.Inventory; -/// -/// Request body for product creation. -/// public sealed record CreateProductRequest( string Name, Guid CategoryId, - decimal CostPrice, - decimal SalePrice, - decimal ItbisRate, - int UnitType); + decimal ItbisRate); -/// -/// Request body for price updates. -/// public sealed record UpdatePriceRequest(decimal NewCostPrice, decimal NewSalePrice); -/// -/// Request body for stock adjustments. -/// public sealed record AdjustStockRequest(decimal Delta, string Reason); -/// -/// Created product API response. -/// public sealed record CreatedProductResponse(Guid ProductId); -/// -/// Standard API error payload. -/// public sealed record ApiErrorResponse(string Error, string Message, int StatusCode); -/// -/// Request body for category creation. -/// public sealed record CreateCategoryRequest(string Name); + +// Presentations +public sealed record UpdatePresentationPriceRequest(decimal SalePrice, decimal CostPrice); + +public sealed record AddPresentationRequest( + string DisplayName, + int PresentationType, + int SellMode, + int MeasureUnit, + decimal SalePrice, + decimal CostPrice, + string? Brand, + decimal? NominalCapacity); + +// Stock entries +public sealed record StockEntryLineRequest( + Guid PresentationId, + int ContainerCount, + int UnitsPerContainer, + decimal NominalSizePerUnit, + decimal CostPerUnit); + +public sealed record ConfirmStockEntryRequest( + DateTime PurchasedAt, + string? SupplierName, + string? Notes, + Guid? FundId, + string? FundExpenseJustification, + List Lines); + +// Container operations +public sealed record OpenContainerRequest(decimal? ActualCapacity); + +public sealed record DrawFromContainerRequest(decimal Amount, bool AllowOverDraw = false); + +public sealed record SetActiveContainerRequest(Guid ContainerId); + +// Monetary fund +public sealed record CreateFundRequest(string Name, decimal InitialDeposit); + +public sealed record FundDepositRequest(decimal Amount, string Description); + +public sealed record FundExpenseRequest( + decimal Amount, + int Category, + string Description, + string? JustificationNote, + Guid? ReferenceId); diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryEndpoints.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryEndpoints.cs index 015840c..9aa17d4 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryEndpoints.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Inventory/InventoryEndpoints.cs @@ -5,156 +5,102 @@ namespace TuColmadoRD.Presentation.API.Endpoints.Inventory; -/// -/// Minimal API endpoints for inventory module with API versioning support. -/// All endpoints use /api/v1/ prefix for versioning. -/// public static class InventoryEndpoints { - /// - /// Maps inventory endpoint group with versioning. - /// public static IEndpointRouteBuilder MapInventoryEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/api/v1/inventory") .WithTags("Inventory") .RequireAuthorization(); - group.MapPost("/products", CreateProduct) - .WithName("CreateProduct") - .WithOpenApi(); - - group.MapPut("/products/{id:guid}/price", UpdatePrice) - .WithName("UpdateProductPrice") - .WithOpenApi(); - - group.MapPost("/products/{id:guid}/stock/adjust", AdjustStock) - .WithName("AdjustStock") - .WithOpenApi(); - - group.MapDelete("/products/{id:guid}", DeactivateProduct) - .WithName("DeactivateProduct") - .WithOpenApi(); - - group.MapGet("/products/{id:guid}", GetProductById) - .WithName("GetProductById") - .WithOpenApi(); - - group.MapGet("/products", GetProductsPaged) - .WithName("GetProductsPaged") - .WithOpenApi(); - - group.MapGet("/catalog", GetCatalog) - .WithName("GetCatalog") - .WithOpenApi(); - - group.MapGet("/products/low-stock", GetLowStock) - .WithName("GetLowStockProducts") - .WithOpenApi(); - - group.MapGet("/categories", GetCategories) - .WithName("GetCategories") - .WithOpenApi(); - - group.MapPost("/categories", CreateCategory) - .WithName("CreateCategory") - .WithOpenApi(); - - group.MapPost("/categories/seed-defaults", SeedDefaultCategories) - .WithName("SeedDefaultCategories") - .WithOpenApi(); - - group.MapDelete("/categories/{id:guid}", DeactivateCategory) - .WithName("DeactivateCategory") - .WithOpenApi(); + // Products + group.MapPost("/products", CreateProduct).WithName("CreateProduct").WithOpenApi(); + group.MapDelete("/products/{id:guid}", DeactivateProduct).WithName("DeactivateProduct").WithOpenApi(); + group.MapGet("/products/{id:guid}", GetProductById).WithName("GetProductById").WithOpenApi(); + group.MapGet("/products", GetProductsPaged).WithName("GetProductsPaged").WithOpenApi(); + group.MapGet("/catalog", GetCatalog).WithName("GetCatalog").WithOpenApi(); + + // Legacy stubbed endpoints (return deprecation error via handler) + group.MapPut("/products/{id:guid}/price", UpdatePrice).WithName("UpdateProductPrice").WithOpenApi(); + group.MapPost("/products/{id:guid}/stock/adjust", AdjustStock).WithName("AdjustStock").WithOpenApi(); + group.MapGet("/products/low-stock", GetLowStock).WithName("GetLowStockProducts").WithOpenApi(); + + // Presentations + group.MapPost("/products/{id:guid}/presentations", AddPresentation).WithName("AddPresentation").WithOpenApi(); + group.MapGet("/products/{id:guid}/presentations", GetPresentationsByProduct).WithName("GetPresentationsByProduct").WithOpenApi(); + group.MapDelete("/presentations/{id:guid}", DeactivatePresentation).WithName("DeactivatePresentation").WithOpenApi(); + group.MapPut("/presentations/{id:guid}/price", UpdatePresentationPrice).WithName("UpdatePresentationPrice").WithOpenApi(); + + // Stock entries + group.MapPost("/stock-entries", ConfirmStockEntry).WithName("ConfirmStockEntry").WithOpenApi(); + group.MapGet("/stock-entries", GetStockEntries).WithName("GetStockEntries").WithOpenApi(); + + // Container operations + group.MapGet("/presentations/{id:guid}/containers", GetContainersByPresentation).WithName("GetContainersByPresentation").WithOpenApi(); + group.MapPost("/containers/{id:guid}/open", OpenContainer).WithName("OpenContainer").WithOpenApi(); + group.MapPost("/containers/{id:guid}/draw", DrawFromContainer).WithName("DrawFromContainer").WithOpenApi(); + group.MapPost("/containers/{id:guid}/empty", MarkContainerEmpty).WithName("MarkContainerEmpty").WithOpenApi(); + group.MapPut("/presentations/{id:guid}/active-container", SetActiveContainer).WithName("SetActiveContainer").WithOpenApi(); + + // Monetary fund + group.MapGet("/funds", GetFunds).WithName("GetFunds").WithOpenApi(); + group.MapPost("/funds", CreateFund).WithName("CreateFund").WithOpenApi(); + group.MapGet("/funds/{id:guid}", GetFund).WithName("GetFund").WithOpenApi(); + group.MapPost("/funds/{id:guid}/deposit", FundDeposit).WithName("FundDeposit").WithOpenApi(); + group.MapPost("/funds/{id:guid}/expense", FundExpense).WithName("FundExpense").WithOpenApi(); + group.MapGet("/funds/{id:guid}/transactions", GetFundTransactions).WithName("GetFundTransactions").WithOpenApi(); + + // Categories + group.MapGet("/categories", GetCategories).WithName("GetCategories").WithOpenApi(); + group.MapPost("/categories", CreateCategory).WithName("CreateCategory").WithOpenApi(); + group.MapPost("/categories/seed-defaults", SeedDefaultCategories).WithName("SeedDefaultCategories").WithOpenApi(); + group.MapDelete("/categories/{id:guid}", DeactivateCategory).WithName("DeactivateCategory").WithOpenApi(); return app; } + // ── Products ───────────────────────────────────────────────────────────── + private static async Task CreateProduct( - CreateProductRequest request, - IMediator mediator, - CancellationToken ct) + CreateProductRequest request, IMediator mediator, CancellationToken ct) { - var command = new CreateProductCommand( - request.Name, - request.CategoryId, - request.CostPrice, - request.SalePrice, - request.ItbisRate, - request.UnitType); - + var command = new CreateProductCommand(request.Name, request.CategoryId, request.ItbisRate); var result = await mediator.Send(command, ct); if (!result.TryGetResult(out var productId)) - { return result.Error.MapDomainError(); - } return TypedResults.Created($"/api/v1/inventory/products/{productId}", new CreatedProductResponse(productId)); } private static async Task UpdatePrice( - Guid id, - UpdatePriceRequest request, - IMediator mediator, - CancellationToken ct) + Guid id, UpdatePriceRequest request, IMediator mediator, CancellationToken ct) { var command = new UpdateProductPriceCommand(id, request.NewCostPrice, request.NewSalePrice); var result = await mediator.Send(command, ct); - if (!result.IsGood) - { - return result.Error.MapDomainError(); - } - - return TypedResults.Ok(new { }); + return result.IsGood ? TypedResults.Ok(new { }) : result.Error.MapDomainError(); } private static async Task AdjustStock( - Guid id, - AdjustStockRequest request, - IMediator mediator, - CancellationToken ct) + Guid id, AdjustStockRequest request, IMediator mediator, CancellationToken ct) { var command = new AdjustStockCommand(id, request.Delta, request.Reason); var result = await mediator.Send(command, ct); - if (!result.IsGood) - { - return result.Error.MapDomainError(); - } - - var productResult = await mediator.Send(new GetProductByIdQuery(id), ct); - if (!productResult.TryGetResult(out var product)) - { - return productResult.Error.MapDomainError(); - } - - return TypedResults.Ok(new { newStockQuantity = product!.StockQuantity }); + return result.IsGood ? TypedResults.Ok(new { }) : result.Error.MapDomainError(); } private static async Task DeactivateProduct( - Guid id, - IMediator mediator, - CancellationToken ct) + Guid id, IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new DeactivateProductCommand(id), ct); - if (!result.IsGood) - { - return result.Error.MapDomainError(); - } - - return TypedResults.NoContent(); + return result.IsGood ? TypedResults.NoContent() : result.Error.MapDomainError(); } private static async Task GetProductById( - Guid id, - IMediator mediator, - CancellationToken ct) + Guid id, IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new GetProductByIdQuery(id), ct); if (!result.TryGetResult(out var dto)) - { return result.Error.MapDomainError(); - } return TypedResults.Ok(dto); } @@ -171,44 +117,224 @@ private static async Task GetProductsPaged( var query = new GetProductsPagedQuery(page, pageSize, nameFilter, categoryId, includeInactive); var result = await mediator.Send(query, ct); if (!result.TryGetResult(out var dto)) - { return result.Error.MapDomainError(); - } return TypedResults.Ok(dto); } - private static async Task GetCatalog( - IMediator mediator, - CancellationToken ct) + private static async Task GetCatalog(IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new GetCatalogQuery(), ct); if (!result.TryGetResult(out var dtos)) - { return result.Error.MapDomainError(); - } return TypedResults.Ok(dtos); } private static async Task GetLowStock( - IMediator mediator, - int threshold = 5, - CancellationToken ct = default) + IMediator mediator, int threshold = 5, CancellationToken ct = default) { threshold = Math.Clamp(threshold, 0, 100); var result = await mediator.Send(new GetLowStockQuery(threshold), ct); if (!result.TryGetResult(out var response)) - { return result.Error.MapDomainError(); - } return TypedResults.Ok(response); } - private static async Task GetCategories( - IMediator mediator, - CancellationToken ct) + // ── Presentations ───────────────────────────────────────────────────────── + + private static async Task AddPresentation( + Guid id, AddPresentationRequest request, IMediator mediator, CancellationToken ct) + { + var command = new AddProductPresentationCommand( + id, + request.DisplayName, + request.PresentationType, + request.SellMode, + request.MeasureUnit, + request.SalePrice, + request.CostPrice, + request.Brand, + request.NominalCapacity); + + var result = await mediator.Send(command, ct); + if (!result.TryGetResult(out var presentationId)) + return result.Error.MapDomainError(); + + return TypedResults.Created($"/api/v1/inventory/presentations/{presentationId}", new { presentationId }); + } + + private static async Task DeactivatePresentation( + Guid id, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new DeactivatePresentationCommand(id), ct); + return result.IsGood ? TypedResults.NoContent() : result.Error.MapDomainError(); + } + + private static async Task UpdatePresentationPrice( + Guid id, UpdatePresentationPriceRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new UpdatePresentationPriceCommand(id, request.SalePrice, request.CostPrice), ct); + return result.IsGood ? TypedResults.Ok(new { }) : result.Error.MapDomainError(); + } + + private static async Task GetPresentationsByProduct( + Guid id, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new GetPresentationsByProductQuery(id), ct); + if (!result.TryGetResult(out var dtos)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(dtos); + } + + // ── Stock Entries ───────────────────────────────────────────────────────── + + private static async Task ConfirmStockEntry( + ConfirmStockEntryRequest request, IMediator mediator, CancellationToken ct) + { + var lines = request.Lines + .Select(l => new StockEntryLineDto( + l.PresentationId, l.ContainerCount, l.UnitsPerContainer, + l.NominalSizePerUnit, l.CostPerUnit)) + .ToList(); + + var command = new ConfirmStockEntryCommand( + request.PurchasedAt, + request.SupplierName, + request.Notes, + request.FundId, + request.FundExpenseJustification, + lines); + + var result = await mediator.Send(command, ct); + if (!result.TryGetResult(out var entryId)) + return result.Error.MapDomainError(); + + return TypedResults.Created($"/api/v1/inventory/stock-entries/{entryId}", new { entryId }); + } + + private static async Task GetStockEntries( + IMediator mediator, int page = 1, int pageSize = 20, CancellationToken ct = default) + { + var result = await mediator.Send(new GetStockEntriesQuery(page, pageSize), ct); + if (!result.TryGetResult(out var paged)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(paged); + } + + // ── Containers ──────────────────────────────────────────────────────────── + + private static async Task GetContainersByPresentation( + Guid id, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new GetContainersByPresentationQuery(id), ct); + if (!result.TryGetResult(out var dtos)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(dtos); + } + + private static async Task OpenContainer( + Guid id, OpenContainerRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new OpenContainerCommand(id, request.ActualCapacity), ct); + return result.IsGood ? TypedResults.Ok(new { }) : result.Error.MapDomainError(); + } + + private static async Task DrawFromContainer( + Guid id, DrawFromContainerRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new DrawFromContainerCommand(id, request.Amount, request.AllowOverDraw), ct); + if (!result.TryGetResult(out var remaining)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(new { remaining }); + } + + private static async Task MarkContainerEmpty( + Guid id, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new MarkContainerEmptyCommand(id), ct); + return result.IsGood ? TypedResults.NoContent() : result.Error.MapDomainError(); + } + + private static async Task SetActiveContainer( + Guid id, SetActiveContainerRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new SetActiveContainerCommand(id, request.ContainerId), ct); + return result.IsGood ? TypedResults.Ok(new { }) : result.Error.MapDomainError(); + } + + private static async Task GetFunds(IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new GetFundsQuery(), ct); + if (!result.TryGetResult(out var funds)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(funds); + } + + private static async Task GetFundTransactions( + Guid id, IMediator mediator, int page = 1, int pageSize = 20, CancellationToken ct = default) + { + var result = await mediator.Send(new GetFundTransactionsQuery(id, page, pageSize), ct); + if (!result.TryGetResult(out var paged)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(paged); + } + + // ── Monetary Fund ───────────────────────────────────────────────────────── + + private static async Task CreateFund( + CreateFundRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new CreateMonetaryFundCommand(request.Name, request.InitialDeposit), ct); + if (!result.TryGetResult(out var fundId)) + return result.Error.MapDomainError(); + + return TypedResults.Created($"/api/v1/inventory/funds/{fundId}", new { fundId }); + } + + private static async Task GetFund( + Guid id, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new GetMonetaryFundQuery(id), ct); + if (!result.TryGetResult(out var response)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(response); + } + + private static async Task FundDeposit( + Guid id, FundDepositRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new RecordFundDepositCommand(id, request.Amount, request.Description), ct); + if (!result.TryGetResult(out var transactionId)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(new { transactionId }); + } + + private static async Task FundExpense( + Guid id, FundExpenseRequest request, IMediator mediator, CancellationToken ct) + { + var result = await mediator.Send(new RecordFundExpenseCommand( + id, request.Amount, request.Category, + request.Description, request.JustificationNote, request.ReferenceId), ct); + + if (!result.TryGetResult(out var transactionId)) + return result.Error.MapDomainError(); + + return TypedResults.Ok(new { transactionId }); + } + + // ── Categories ──────────────────────────────────────────────────────────── + + private static async Task GetCategories(IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new GetCategoriesQuery(), ct); if (!result.TryGetResult(out var categories)) @@ -218,9 +344,7 @@ private static async Task GetCategories( } private static async Task CreateCategory( - CreateCategoryRequest request, - IMediator mediator, - CancellationToken ct) + CreateCategoryRequest request, IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new CreateCategoryCommand(request.Name), ct); if (!result.TryGetResult(out var id)) @@ -229,9 +353,7 @@ private static async Task CreateCategory( return TypedResults.Created($"/api/v1/inventory/categories/{id}", new { id }); } - private static async Task SeedDefaultCategories( - IMediator mediator, - CancellationToken ct) + private static async Task SeedDefaultCategories(IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new SeedDefaultCategoriesCommand(), ct); if (!result.TryGetResult(out var count)) @@ -241,14 +363,9 @@ private static async Task SeedDefaultCategories( } private static async Task DeactivateCategory( - Guid id, - IMediator mediator, - CancellationToken ct) + Guid id, IMediator mediator, CancellationToken ct) { var result = await mediator.Send(new DeactivateCategoryCommand(id), ct); - if (!result.IsGood) - return result.Error.MapDomainError(); - - return TypedResults.NoContent(); + return result.IsGood ? TypedResults.NoContent() : result.Error.MapDomainError(); } } diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesContracts.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesContracts.cs index 49f45ef..3302146 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesContracts.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesContracts.cs @@ -1,6 +1,6 @@ namespace TuColmadoRD.Presentation.API.Endpoints.Sales; -public sealed record SaleItemRequest(Guid ProductId, decimal Quantity); +public sealed record SaleItemRequest(Guid ProductId, Guid PresentationId, decimal Quantity); public sealed record SalePaymentRequest(int PaymentMethodId, decimal Amount, string? Reference, Guid? CustomerId); diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesEndpoints.cs b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesEndpoints.cs index 30b6fae..eb48d1d 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesEndpoints.cs +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/Endpoints/Sales/SalesEndpoints.cs @@ -41,7 +41,7 @@ private static async Task CreateSale( IMediator mediator, CancellationToken ct) { - var commandItems = request.Items.Select(i => new ApplicationSaleItemRequest(i.ProductId, i.Quantity)).ToList(); + var commandItems = request.Items.Select(i => new ApplicationSaleItemRequest(i.ProductId, i.PresentationId, i.Quantity)).ToList(); var commandPayments = request.Payments.Select(p => new ApplicationSalePaymentRequest(p.PaymentMethodId, p.Amount, p.Reference, p.CustomerId)).ToList(); ApplicationDeliveryAddressRequest? deliveryAddress = null; diff --git a/backend/src/Presentations/TuColmadoRD.Presentation.API/TuColmadoRD.Presentation.API.csproj b/backend/src/Presentations/TuColmadoRD.Presentation.API/TuColmadoRD.Presentation.API.csproj index b12c73b..9f6d09d 100644 --- a/backend/src/Presentations/TuColmadoRD.Presentation.API/TuColmadoRD.Presentation.API.csproj +++ b/backend/src/Presentations/TuColmadoRD.Presentation.API/TuColmadoRD.Presentation.API.csproj @@ -5,6 +5,7 @@ Exe enable enable + true @@ -23,12 +24,12 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IMonetaryFundRepository.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IMonetaryFundRepository.cs new file mode 100644 index 0000000..e6e8211 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IMonetaryFundRepository.cs @@ -0,0 +1,13 @@ +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Abstractions; + +public interface IMonetaryFundRepository +{ + Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default); + Task GetDefaultAsync(Guid tenantId, CancellationToken ct = default); + Task> GetAllAsync(Guid tenantId, CancellationToken ct = default); + Task AddAsync(MonetaryFund fund, CancellationToken ct = default); +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPackagedStockRepository.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPackagedStockRepository.cs new file mode 100644 index 0000000..3575af4 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPackagedStockRepository.cs @@ -0,0 +1,11 @@ +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Abstractions; + +public interface IPackagedStockRepository +{ + Task GetByPresentationIdAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default); + Task AddAsync(PackagedStock stock, CancellationToken ct = default); +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPresentationRepository.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPresentationRepository.cs new file mode 100644 index 0000000..07aa88f --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IPresentationRepository.cs @@ -0,0 +1,13 @@ +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Abstractions; + +public interface IPresentationRepository +{ + Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default); + Task> GetByProductIdAsync(Guid productId, Guid tenantId, CancellationToken ct = default); + Task AddAsync(ProductPresentation presentation, CancellationToken ct = default); + Task ProductExistsAsync(Guid productId, Guid tenantId, CancellationToken ct = default); +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockContainerRepository.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockContainerRepository.cs new file mode 100644 index 0000000..8f289c0 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockContainerRepository.cs @@ -0,0 +1,14 @@ +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Abstractions; + +public interface IStockContainerRepository +{ + Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default); + Task> GetByPresentationIdAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default); + Task GetActiveSourceAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default); + Task AddRangeAsync(IEnumerable containers, CancellationToken ct = default); + Task NextContainerCodeAsync(Guid tenantId, CancellationToken ct = default); +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockEntryRepository.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockEntryRepository.cs new file mode 100644 index 0000000..69bef93 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Abstractions/IStockEntryRepository.cs @@ -0,0 +1,8 @@ +using TuColmadoRD.Core.Domain.Entities.Inventory; + +namespace TuColmadoRD.Core.Application.Inventory.Abstractions; + +public interface IStockEntryRepository +{ + Task AddAsync(StockEntry entry, CancellationToken ct = default); +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/AddProductPresentationCommand.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/AddProductPresentationCommand.cs new file mode 100644 index 0000000..61c920a --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/AddProductPresentationCommand.cs @@ -0,0 +1,18 @@ +using MediatR; +using TuColmadoRD.Core.Application.Behaviors; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Commands; + +public record AddProductPresentationCommand( + Guid ProductId, + string DisplayName, + int PresentationType, + int SellMode, + int MeasureUnit, + decimal SalePrice, + decimal CostPrice, + string? Brand, + decimal? NominalCapacity +) : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ConfirmStockEntryCommand.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ConfirmStockEntryCommand.cs new file mode 100644 index 0000000..55c45ea --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ConfirmStockEntryCommand.cs @@ -0,0 +1,22 @@ +using MediatR; +using TuColmadoRD.Core.Application.Behaviors; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Commands; + +public record StockEntryLineDto( + Guid PresentationId, + int ContainerCount, + int UnitsPerContainer, + decimal NominalSizePerUnit, + decimal CostPerUnit); + +public record ConfirmStockEntryCommand( + DateTime PurchasedAt, + string? SupplierName, + string? Notes, + Guid? FundId, + string? FundExpenseJustification, + IReadOnlyList Lines +) : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ContainerCommands.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ContainerCommands.cs new file mode 100644 index 0000000..abf0ffa --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/ContainerCommands.cs @@ -0,0 +1,27 @@ +using MediatR; +using TuColmadoRD.Core.Application.Behaviors; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Commands; + +public record OpenContainerCommand( + Guid ContainerId, + decimal? ActualCapacity +) : IRequest>, ICommandMarker; + +public record DrawFromContainerCommand( + Guid ContainerId, + decimal Amount, + bool AllowOverDraw = false +) : IRequest>, ICommandMarker; + +public record MarkContainerEmptyCommand( + Guid ContainerId +) : IRequest>, ICommandMarker; + +public record SetActiveContainerCommand( + Guid PresentationId, + Guid ContainerId +) : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/CreateProductCommand.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/CreateProductCommand.cs index 8099d96..1179e9e 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/CreateProductCommand.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/CreateProductCommand.cs @@ -6,13 +6,10 @@ namespace TuColmadoRD.Core.Application.Inventory.Commands; /// -/// Command to create a product. +/// Command to create a product. Prices and unit info live on ProductPresentation. /// public record CreateProductCommand( string Name, Guid CategoryId, - decimal CostPrice, - decimal SalePrice, - decimal ItbisRate, - int UnitType + decimal ItbisRate ) : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/MonetaryFundCommands.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/MonetaryFundCommands.cs new file mode 100644 index 0000000..47b37b4 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/MonetaryFundCommands.cs @@ -0,0 +1,27 @@ +using MediatR; +using TuColmadoRD.Core.Application.Behaviors; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Commands; + +public record CreateMonetaryFundCommand( + string Name, + decimal InitialDeposit +) : IRequest>, ICommandMarker; + +public record RecordFundDepositCommand( + Guid FundId, + decimal Amount, + string Description +) : IRequest>, ICommandMarker; + +public record RecordFundExpenseCommand( + Guid FundId, + decimal Amount, + int Category, + string Description, + string? JustificationNote, + Guid? ReferenceId +) : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/PresentationCommands.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/PresentationCommands.cs new file mode 100644 index 0000000..ca1a723 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Commands/PresentationCommands.cs @@ -0,0 +1,13 @@ +using MediatR; +using TuColmadoRD.Core.Application.Behaviors; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Commands; + +public record DeactivatePresentationCommand(Guid PresentationId) + : IRequest>, ICommandMarker; + +public record UpdatePresentationPriceCommand(Guid PresentationId, decimal NewSalePrice, decimal NewCostPrice) + : IRequest>, ICommandMarker; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ContainerDto.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ContainerDto.cs new file mode 100644 index 0000000..428a7ac --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ContainerDto.cs @@ -0,0 +1,16 @@ +namespace TuColmadoRD.Core.Application.Inventory.DTOs; + +public sealed record ContainerDto( + Guid Id, + Guid PresentationId, + string ContainerCode, + decimal NominalCapacity, + decimal? ActualCapacity, + decimal CurrentRemaining, + string Status, + bool IsActiveSource, + string Notes, + DateTime PurchasedAt, + DateTime? OpenedAt, + DateTime? EmptiedAt, + DateTime CreatedAt); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/MonetaryFundDto.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/MonetaryFundDto.cs new file mode 100644 index 0000000..51b7e67 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/MonetaryFundDto.cs @@ -0,0 +1,26 @@ +namespace TuColmadoRD.Core.Application.Inventory.DTOs; + +public sealed record MonetaryFundDto( + Guid Id, + Guid TenantId, + string Name, + decimal CurrentBalance, + DateTime CreatedAt); + +public sealed record FundTransactionDto( + Guid Id, + Guid FundId, + int Type, + string TypeName, + decimal Amount, + int? Category, + string? CategoryName, + string Description, + string? JustificationNote, + Guid? ReferenceId, + decimal BalanceAfter, + DateTime OccurredAt); + +public sealed record FundBalanceResponse( + MonetaryFundDto Fund, + IReadOnlyList RecentTransactions); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/PresentationDto.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/PresentationDto.cs new file mode 100644 index 0000000..fcc84b9 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/PresentationDto.cs @@ -0,0 +1,18 @@ +namespace TuColmadoRD.Core.Application.Inventory.DTOs; + +public sealed record PresentationDto( + Guid Id, + Guid ProductId, + string DisplayName, + int PresentationTypeId, + string PresentationTypeName, + int SellModeId, + string SellModeName, + int MeasureUnit, + string? Brand, + decimal? NominalCapacity, + decimal SalePrice, + decimal CostPrice, + bool IsActive, + DateTime CreatedAt, + DateTime UpdatedAt); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductCreatedPayload.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductCreatedPayload.cs index 6fc40df..9ff5608 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductCreatedPayload.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductCreatedPayload.cs @@ -8,8 +8,5 @@ public sealed record ProductCreatedPayload( Guid TenantId, string Name, Guid CategoryId, - decimal CostPrice, - decimal SalePrice, decimal ItbisRate, - int UnitType, DateTime CreatedAt); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductDto.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductDto.cs index 5042827..c1b2460 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductDto.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/DTOs/ProductDto.cs @@ -8,11 +8,6 @@ public sealed record ProductDto( string Name, Guid CategoryId, string CategoryName, - decimal CostPrice, - decimal SalePrice, decimal ItbisRate, - int UnitTypeId, - string UnitTypeName, - decimal StockQuantity, bool IsActive, DateTime UpdatedAt); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AddProductPresentationCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AddProductPresentationCommandHandler.cs new file mode 100644 index 0000000..8826738 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AddProductPresentationCommandHandler.cs @@ -0,0 +1,87 @@ +using System.Text.Json; +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Commands; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Entities.System; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class AddProductPresentationCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IPresentationRepository _presentationRepository; + private readonly IOutboxRepository _outboxRepository; + private readonly IUnitOfWork _unitOfWork; + + public AddProductPresentationCommandHandler( + ITenantProvider tenantProvider, + IPresentationRepository presentationRepository, + IOutboxRepository outboxRepository, + IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _presentationRepository = presentationRepository; + _outboxRepository = outboxRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + AddProductPresentationCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + + var productExists = await _presentationRepository.ProductExistsAsync( + request.ProductId, tenantId, cancellationToken); + if (!productExists) + return OperationResult.Bad(DomainError.NotFound("product.not_found")); + + var salePriceResult = Money.FromDecimal(request.SalePrice); + if (!salePriceResult.TryGetResult(out var salePrice)) + return OperationResult.Bad(salePriceResult.Error); + + var costPriceResult = Money.FromDecimal(request.CostPrice); + if (!costPriceResult.TryGetResult(out var costPrice)) + return OperationResult.Bad(costPriceResult.Error); + + var presentationTypeResult = PresentationType.FromId(request.PresentationType); + if (!presentationTypeResult.TryGetResult(out var presentationType)) + return OperationResult.Bad(presentationTypeResult.Error); + + var sellModeResult = SellMode.FromId(request.SellMode); + if (!sellModeResult.TryGetResult(out var sellMode)) + return OperationResult.Bad(sellModeResult.Error); + + var measureUnit = (UnitOfMeasure)request.MeasureUnit; + + var presentationResult = ProductPresentation.Create( + tenantId, request.ProductId, request.DisplayName, + presentationType!, sellMode!, measureUnit, + salePrice!, costPrice!, request.Brand, request.NominalCapacity); + + if (!presentationResult.TryGetResult(out var presentation)) + return OperationResult.Bad(presentationResult.Error); + + var outboxMessage = new OutboxMessage("PresentationCreated", + JsonSerializer.Serialize(new + { + presentation!.Id, + presentation.ProductId, + TenantId = tenantId, + presentation.DisplayName, + OccurredAt = DateTime.UtcNow + })); + + await _presentationRepository.AddAsync(presentation!, cancellationToken); + await _outboxRepository.AddAsync(outboxMessage, cancellationToken); + await _unitOfWork.CommitAsync(cancellationToken); + + return OperationResult.Good(presentation!.Id); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AdjustStockCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AdjustStockCommandHandler.cs index 9c66d55..7ce89f4 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AdjustStockCommandHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/AdjustStockCommandHandler.cs @@ -33,34 +33,10 @@ public AdjustStockCommandHandler( _unitOfWork = unitOfWork; } - public async Task> Handle(AdjustStockCommand request, CancellationToken cancellationToken) + public Task> Handle(AdjustStockCommand request, CancellationToken cancellationToken) { - var tenantId = (Guid)_tenantProvider.TenantId; - - var productResult = await _productRepository.GetByIdAsync(request.ProductId, tenantId, cancellationToken); - if (!productResult.TryGetResult(out var product) || product is null) - { - return OperationResult.Bad(productResult.Error); - } - - var adjustResult = product.AdjustStock(request.Delta); - if (!adjustResult.IsGood) - { - return adjustResult; - } - - var payload = new StockAdjustedPayload( - product.Id, - tenantId, - request.Delta, - product.StockQuantity, - request.Reason, - product.UpdatedAt); - - var outboxMessage = new OutboxMessage("StockAdjusted", JsonSerializer.Serialize(payload)); - await _outboxRepository.AddAsync(outboxMessage, cancellationToken); - await _unitOfWork.CommitAsync(cancellationToken); - - return OperationResult.Good(ResultUnit.Value); + return Task.FromResult(OperationResult.Bad( + DomainError.Business("stock.operation_deprecated", + "Stock is now tracked per presentation. Use DrawFromContainerCommand or ConfirmStockEntryCommand."))); } } diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ConfirmStockEntryCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ConfirmStockEntryCommandHandler.cs new file mode 100644 index 0000000..d3b3dbd --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ConfirmStockEntryCommandHandler.cs @@ -0,0 +1,157 @@ +using System.Text.Json; +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Commands; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Entities.System; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class ConfirmStockEntryCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IPresentationRepository _presentationRepository; + private readonly IStockContainerRepository _containerRepository; + private readonly IPackagedStockRepository _packagedStockRepository; + private readonly IStockEntryRepository _stockEntryRepository; + private readonly IMonetaryFundRepository _fundRepository; + private readonly IOutboxRepository _outboxRepository; + private readonly IUnitOfWork _unitOfWork; + + public ConfirmStockEntryCommandHandler( + ITenantProvider tenantProvider, + IPresentationRepository presentationRepository, + IStockContainerRepository containerRepository, + IPackagedStockRepository packagedStockRepository, + IStockEntryRepository stockEntryRepository, + IMonetaryFundRepository fundRepository, + IOutboxRepository outboxRepository, + IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _presentationRepository = presentationRepository; + _containerRepository = containerRepository; + _packagedStockRepository = packagedStockRepository; + _stockEntryRepository = stockEntryRepository; + _fundRepository = fundRepository; + _outboxRepository = outboxRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + ConfirmStockEntryCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + + if (request.Lines is null || request.Lines.Count == 0) + return OperationResult.Bad(DomainError.Validation("stock_entry.must_have_at_least_one_line")); + + var entryResult = StockEntry.Create(tenantId, request.PurchasedAt, request.SupplierName, request.Notes); + if (!entryResult.TryGetResult(out var entry)) + return OperationResult.Bad(entryResult.Error); + + var newContainers = new List(); + var stockToUpdate = new List<(PackagedStock stock, int units)>(); + + foreach (var lineDto in request.Lines) + { + var presentationResult = await _presentationRepository.GetByIdAsync( + lineDto.PresentationId, tenantId, cancellationToken); + if (!presentationResult.TryGetResult(out var presentation)) + return OperationResult.Bad(presentationResult.Error); + + var costPerUnitResult = Money.FromDecimal(lineDto.CostPerUnit); + if (!costPerUnitResult.TryGetResult(out var costPerUnit)) + return OperationResult.Bad(costPerUnitResult.Error); + + var addLineResult = entry!.AddLine( + lineDto.PresentationId, lineDto.ContainerCount, + lineDto.UnitsPerContainer, lineDto.NominalSizePerUnit, costPerUnit!); + if (!addLineResult.IsGood) + return OperationResult.Bad(addLineResult.Error); + + if (presentation!.PresentationType == PresentationType.BulkContainer) + { + for (int i = 0; i < lineDto.ContainerCount; i++) + { + var code = await _containerRepository.NextContainerCodeAsync(tenantId, cancellationToken); + var containerResult = StockContainer.Create( + tenantId, lineDto.PresentationId, code, + lineDto.NominalSizePerUnit, null, request.PurchasedAt, null); + if (!containerResult.TryGetResult(out var container)) + return OperationResult.Bad(containerResult.Error); + + newContainers.Add(container!); + } + } + else + { + var existing = await _packagedStockRepository.GetByPresentationIdAsync( + lineDto.PresentationId, tenantId, cancellationToken); + + if (existing is null) + { + var newStockResult = PackagedStock.Create(tenantId, lineDto.PresentationId); + if (!newStockResult.TryGetResult(out var newStock)) + return OperationResult.Bad(newStockResult.Error); + + newStock!.Add(lineDto.ContainerCount * lineDto.UnitsPerContainer); + await _packagedStockRepository.AddAsync(newStock, cancellationToken); + } + else + { + stockToUpdate.Add((existing, lineDto.ContainerCount * lineDto.UnitsPerContainer)); + } + } + } + + var confirmResult = entry!.Confirm(); + if (!confirmResult.IsGood) + return OperationResult.Bad(confirmResult.Error); + + // Optionally charge monetary fund + if (request.FundId.HasValue) + { + var fundResult = await _fundRepository.GetByIdAsync(request.FundId.Value, tenantId, cancellationToken); + if (fundResult.TryGetResult(out var fund) && fund is not null) + { + var expenseResult = fund.RecordExpense( + entry.TotalCost, + FundExpenseCategory.StockPurchase, + $"Entrada de stock #{entry.Id}", + request.FundExpenseJustification); + + if (expenseResult.TryGetResult(out var tx) && tx is not null) + entry.LinkFundTransaction(tx.Id); + } + } + + foreach (var (stock, units) in stockToUpdate) + stock.Add(units); + + if (newContainers.Count > 0) + await _containerRepository.AddRangeAsync(newContainers, cancellationToken); + + await _stockEntryRepository.AddAsync(entry, cancellationToken); + + var outboxMessage = new OutboxMessage("StockEntryConfirmed", + JsonSerializer.Serialize(new + { + EntryId = entry.Id, + TenantId = tenantId, + entry.TotalCost.Amount, + LineCount = request.Lines.Count, + OccurredAt = DateTime.UtcNow + })); + await _outboxRepository.AddAsync(outboxMessage, cancellationToken); + await _unitOfWork.CommitAsync(cancellationToken); + + return OperationResult.Good(entry.Id); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ContainerCommandHandlers.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ContainerCommandHandlers.cs new file mode 100644 index 0000000..8b741d0 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/ContainerCommandHandlers.cs @@ -0,0 +1,146 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Commands; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class OpenContainerCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IStockContainerRepository _containerRepository; + private readonly IUnitOfWork _unitOfWork; + + public OpenContainerCommandHandler(ITenantProvider tenantProvider, + IStockContainerRepository containerRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _containerRepository = containerRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + OpenContainerCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var result = await _containerRepository.GetByIdAsync(request.ContainerId, tenantId, cancellationToken); + if (!result.TryGetResult(out var container)) + return OperationResult.Bad(result.Error); + + if (request.ActualCapacity.HasValue) + { + var setResult = container!.SetActualCapacity(request.ActualCapacity.Value); + if (!setResult.IsGood) return setResult; + } + + var openResult = container!.Open(); + if (!openResult.IsGood) return openResult; + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(ResultUnit.Value); + } +} + +public sealed class DrawFromContainerCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IStockContainerRepository _containerRepository; + private readonly IUnitOfWork _unitOfWork; + + public DrawFromContainerCommandHandler(ITenantProvider tenantProvider, + IStockContainerRepository containerRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _containerRepository = containerRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + DrawFromContainerCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var result = await _containerRepository.GetByIdAsync(request.ContainerId, tenantId, cancellationToken); + if (!result.TryGetResult(out var container)) + return OperationResult.Bad(result.Error); + + var drawResult = container!.Draw(request.Amount, request.AllowOverDraw); + if (!drawResult.IsGood) + return OperationResult.Bad(drawResult.Error); + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(container.CurrentRemaining); + } +} + +public sealed class MarkContainerEmptyCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IStockContainerRepository _containerRepository; + private readonly IUnitOfWork _unitOfWork; + + public MarkContainerEmptyCommandHandler(ITenantProvider tenantProvider, + IStockContainerRepository containerRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _containerRepository = containerRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + MarkContainerEmptyCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var result = await _containerRepository.GetByIdAsync(request.ContainerId, tenantId, cancellationToken); + if (!result.TryGetResult(out var container)) + return OperationResult.Bad(result.Error); + + var emptyResult = container!.MarkEmpty(); + if (!emptyResult.IsGood) return emptyResult; + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(ResultUnit.Value); + } +} + +public sealed class SetActiveContainerCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IStockContainerRepository _containerRepository; + private readonly IUnitOfWork _unitOfWork; + + public SetActiveContainerCommandHandler(ITenantProvider tenantProvider, + IStockContainerRepository containerRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _containerRepository = containerRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + SetActiveContainerCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + + // Deactivate current active source (if any) + var current = await _containerRepository.GetActiveSourceAsync( + request.PresentationId, tenantId, cancellationToken); + current?.SetAsActiveSource(false); + + // Activate the requested one + var targetResult = await _containerRepository.GetByIdAsync( + request.ContainerId, tenantId, cancellationToken); + if (!targetResult.TryGetResult(out var target)) + return OperationResult.Bad(targetResult.Error); + + target!.SetAsActiveSource(true); + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(ResultUnit.Value); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/CreateProductCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/CreateProductCommandHandler.cs index 14d346a..edd5b2b 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/CreateProductCommandHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/CreateProductCommandHandler.cs @@ -7,7 +7,6 @@ using TuColmadoRD.Core.Domain.Base.Result; using TuColmadoRD.Core.Domain.Entities.Inventory; using TuColmadoRD.Core.Domain.Entities.System; -using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; using TuColmadoRD.Core.Domain.ValueObjects; using TuColmadoRD.Core.Domain.ValueObjects.Base; @@ -39,37 +38,19 @@ public async Task> Handle(CreateProductComman { var tenantId = (Guid)_tenantProvider.TenantId; - var costResult = Money.FromDecimal(request.CostPrice); - if (!costResult.TryGetResult(out var costPrice) || costPrice is null) - { - return OperationResult.Bad(costResult.Error); - } - - var saleResult = Money.FromDecimal(request.SalePrice); - if (!saleResult.TryGetResult(out var salePrice) || salePrice is null) - { - return OperationResult.Bad(saleResult.Error); - } - var taxResult = TaxRate.Create(request.ItbisRate); if (!taxResult.TryGetResult(out var itbisRate) || itbisRate is null) { return OperationResult.Bad(taxResult.Error); } - var unitTypeResult = UnitType.FromId(request.UnitType); - if (!unitTypeResult.TryGetResult(out var unitType) || unitType is null) - { - return OperationResult.Bad(unitTypeResult.Error); - } - var categoryExists = await _productRepository.CategoryExistsAsync(request.CategoryId, tenantId, cancellationToken); if (!categoryExists) { return OperationResult.Bad(DomainError.NotFound("category.not_found")); } - var productResult = Product.Create(tenantId, request.Name, request.CategoryId, costPrice, salePrice, itbisRate, unitType); + var productResult = Product.Create(tenantId, request.Name, request.CategoryId, itbisRate!); if (!productResult.TryGetResult(out var product) || product is null) { return OperationResult.Bad(productResult.Error); @@ -80,10 +61,7 @@ public async Task> Handle(CreateProductComman tenantId, product.Name, product.CategoryId, - product.CostPrice, - product.SalePrice, - product.ItbisRate, - product.UnitType, + product.ItbisRate.Rate, product.CreatedAt); var outboxMessage = new OutboxMessage("ProductCreated", JsonSerializer.Serialize(payload)); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetContainersByPresentationQueryHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetContainersByPresentationQueryHandler.cs new file mode 100644 index 0000000..cca93a0 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetContainersByPresentationQueryHandler.cs @@ -0,0 +1,50 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class GetContainersByPresentationQueryHandler + : IRequestHandler, DomainError>> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IStockContainerRepository _containerRepository; + + public GetContainersByPresentationQueryHandler( + ITenantProvider tenantProvider, + IStockContainerRepository containerRepository) + { + _tenantProvider = tenantProvider; + _containerRepository = containerRepository; + } + + public async Task, DomainError>> Handle( + GetContainersByPresentationQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var containers = await _containerRepository.GetByPresentationIdAsync(request.PresentationId, tenantId, cancellationToken); + + var dtos = containers + .Select(c => new ContainerDto( + c.Id, + c.PresentationId, + c.ContainerCode, + c.NominalCapacity, + c.ActualCapacity, + c.CurrentRemaining, + c.Status.Name, + c.IsActiveSource, + c.Notes, + c.PurchasedAt, + c.OpenedAt, + c.EmptiedAt, + c.CreatedAt)) + .ToList(); + + return OperationResult, DomainError>.Good(dtos); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetFundsQueryHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetFundsQueryHandler.cs new file mode 100644 index 0000000..c715830 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetFundsQueryHandler.cs @@ -0,0 +1,37 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class GetFundsQueryHandler + : IRequestHandler, DomainError>> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IMonetaryFundRepository _fundRepository; + + public GetFundsQueryHandler(ITenantProvider tenantProvider, IMonetaryFundRepository fundRepository) + { + _tenantProvider = tenantProvider; + _fundRepository = fundRepository; + } + + public async Task, DomainError>> Handle( + GetFundsQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var funds = await _fundRepository.GetAllAsync(tenantId, cancellationToken); + + var dtos = funds.Select(f => new FundSummaryDto( + f.Id, + f.TenantId.Value, + f.Name, + f.CurrentBalance.Amount, + f.CreatedAt)).ToList(); + + return OperationResult, DomainError>.Good(dtos); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetMonetaryFundQueryHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetMonetaryFundQueryHandler.cs new file mode 100644 index 0000000..d42aeba --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetMonetaryFundQueryHandler.cs @@ -0,0 +1,61 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class GetMonetaryFundQueryHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IMonetaryFundRepository _fundRepository; + + public GetMonetaryFundQueryHandler( + ITenantProvider tenantProvider, + IMonetaryFundRepository fundRepository) + { + _tenantProvider = tenantProvider; + _fundRepository = fundRepository; + } + + public async Task> Handle( + GetMonetaryFundQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var fundResult = await _fundRepository.GetByIdAsync(request.FundId, tenantId, cancellationToken); + if (!fundResult.TryGetResult(out var fund)) + return OperationResult.Bad(fundResult.Error); + + var txDtos = fund!.Transactions + .OrderByDescending(t => t.OccurredAt) + .Take(50) + .Select(t => new FundTransactionDto( + t.Id, + t.FundId, + t.Type.Id, + t.Type.Name, + t.Amount.Amount, + t.Category?.Id, + t.Category?.Name, + t.Description, + t.JustificationNote, + t.ReferenceId, + t.BalanceAfter.Amount, + t.OccurredAt)) + .ToList(); + + var fundDto = new MonetaryFundDto( + fund.Id, + fund.TenantId.Value, + fund.Name, + fund.CurrentBalance.Amount, + fund.CreatedAt); + + return OperationResult.Good( + new FundBalanceResponse(fundDto, txDtos)); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetPresentationsByProductQueryHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetPresentationsByProductQueryHandler.cs new file mode 100644 index 0000000..3c697c7 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/GetPresentationsByProductQueryHandler.cs @@ -0,0 +1,52 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Application.Inventory.Queries; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class GetPresentationsByProductQueryHandler + : IRequestHandler, DomainError>> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IPresentationRepository _presentationRepository; + + public GetPresentationsByProductQueryHandler( + ITenantProvider tenantProvider, + IPresentationRepository presentationRepository) + { + _tenantProvider = tenantProvider; + _presentationRepository = presentationRepository; + } + + public async Task, DomainError>> Handle( + GetPresentationsByProductQuery request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var presentations = await _presentationRepository.GetByProductIdAsync(request.ProductId, tenantId, cancellationToken); + + var dtos = presentations + .Select(p => new PresentationDto( + p.Id, + p.ProductId, + p.DisplayName, + p.PresentationType.Id, + p.PresentationType.Name, + p.SellMode.Id, + p.SellMode.Name, + (int)p.MeasureUnit, + p.Brand, + p.NominalCapacity, + p.SalePrice.Amount, + p.CostPrice.Amount, + p.IsActive, + p.CreatedAt, + p.UpdatedAt)) + .ToList(); + + return OperationResult, DomainError>.Good(dtos); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/MonetaryFundCommandHandlers.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/MonetaryFundCommandHandlers.cs new file mode 100644 index 0000000..f43a697 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/MonetaryFundCommandHandlers.cs @@ -0,0 +1,136 @@ +using System.Text.Json; +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Commands; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Entities.System; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class CreateMonetaryFundCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IMonetaryFundRepository _fundRepository; + private readonly IOutboxRepository _outboxRepository; + private readonly IUnitOfWork _unitOfWork; + + public CreateMonetaryFundCommandHandler(ITenantProvider tenantProvider, + IMonetaryFundRepository fundRepository, + IOutboxRepository outboxRepository, + IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _fundRepository = fundRepository; + _outboxRepository = outboxRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + CreateMonetaryFundCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + + var depositResult = Money.FromDecimal(request.InitialDeposit); + if (!depositResult.TryGetResult(out var deposit)) + return OperationResult.Bad(depositResult.Error); + + var fundResult = MonetaryFund.Create(tenantId, request.Name, deposit!); + if (!fundResult.TryGetResult(out var fund)) + return OperationResult.Bad(fundResult.Error); + + var outboxMessage = new OutboxMessage("MonetaryFundCreated", + JsonSerializer.Serialize(new { fund!.Id, TenantId = tenantId, OccurredAt = DateTime.UtcNow })); + + await _fundRepository.AddAsync(fund, cancellationToken); + await _outboxRepository.AddAsync(outboxMessage, cancellationToken); + await _unitOfWork.CommitAsync(cancellationToken); + + return OperationResult.Good(fund.Id); + } +} + +public sealed class RecordFundDepositCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IMonetaryFundRepository _fundRepository; + private readonly IUnitOfWork _unitOfWork; + + public RecordFundDepositCommandHandler(ITenantProvider tenantProvider, + IMonetaryFundRepository fundRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _fundRepository = fundRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + RecordFundDepositCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var fundResult = await _fundRepository.GetByIdAsync(request.FundId, tenantId, cancellationToken); + if (!fundResult.TryGetResult(out var fund)) + return OperationResult.Bad(fundResult.Error); + + var amountResult = Money.FromDecimal(request.Amount); + if (!amountResult.TryGetResult(out var amount)) + return OperationResult.Bad(amountResult.Error); + + var depositResult = fund!.Deposit(amount!, request.Description); + if (!depositResult.TryGetResult(out var tx)) + return OperationResult.Bad(depositResult.Error); + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(tx!.Id); + } +} + +public sealed class RecordFundExpenseCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IMonetaryFundRepository _fundRepository; + private readonly IUnitOfWork _unitOfWork; + + public RecordFundExpenseCommandHandler(ITenantProvider tenantProvider, + IMonetaryFundRepository fundRepository, IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _fundRepository = fundRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + RecordFundExpenseCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var fundResult = await _fundRepository.GetByIdAsync(request.FundId, tenantId, cancellationToken); + if (!fundResult.TryGetResult(out var fund)) + return OperationResult.Bad(fundResult.Error); + + var amountResult = Money.FromDecimal(request.Amount); + if (!amountResult.TryGetResult(out var amount)) + return OperationResult.Bad(amountResult.Error); + + var categoryResult = FundExpenseCategory.FromId(request.Category); + if (!categoryResult.TryGetResult(out var category)) + return OperationResult.Bad(categoryResult.Error); + + var expenseResult = fund!.RecordExpense( + amount!, category!, request.Description, + request.JustificationNote, request.ReferenceId); + + if (!expenseResult.TryGetResult(out var tx)) + return OperationResult.Bad(expenseResult.Error); + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(tx!.Id); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/PresentationCommandHandlers.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/PresentationCommandHandlers.cs new file mode 100644 index 0000000..cf37928 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/PresentationCommandHandlers.cs @@ -0,0 +1,84 @@ +using MediatR; +using TuColmadoRD.Core.Application.Interfaces.Tenancy; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Application.Inventory.Commands; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using ResultUnit = TuColmadoRD.Core.Domain.Base.Result.Unit; + +namespace TuColmadoRD.Core.Application.Inventory.Handlers; + +public sealed class DeactivatePresentationCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IPresentationRepository _presentationRepository; + private readonly IUnitOfWork _unitOfWork; + + public DeactivatePresentationCommandHandler( + ITenantProvider tenantProvider, + IPresentationRepository presentationRepository, + IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _presentationRepository = presentationRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + DeactivatePresentationCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var result = await _presentationRepository.GetByIdAsync(request.PresentationId, tenantId, cancellationToken); + if (!result.TryGetResult(out var presentation)) + return OperationResult.Bad(result.Error); + + presentation!.Deactivate(); + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(ResultUnit.Value); + } +} + +public sealed class UpdatePresentationPriceCommandHandler + : IRequestHandler> +{ + private readonly ITenantProvider _tenantProvider; + private readonly IPresentationRepository _presentationRepository; + private readonly IUnitOfWork _unitOfWork; + + public UpdatePresentationPriceCommandHandler( + ITenantProvider tenantProvider, + IPresentationRepository presentationRepository, + IUnitOfWork unitOfWork) + { + _tenantProvider = tenantProvider; + _presentationRepository = presentationRepository; + _unitOfWork = unitOfWork; + } + + public async Task> Handle( + UpdatePresentationPriceCommand request, CancellationToken cancellationToken) + { + var tenantId = (Guid)_tenantProvider.TenantId; + var presResult = await _presentationRepository.GetByIdAsync( + request.PresentationId, tenantId, cancellationToken); + if (!presResult.TryGetResult(out var presentation)) + return OperationResult.Bad(presResult.Error); + + var costResult = Money.FromDecimal(request.NewCostPrice); + if (!costResult.TryGetResult(out var cost)) + return OperationResult.Bad(costResult.Error); + + var saleResult = Money.FromDecimal(request.NewSalePrice); + if (!saleResult.TryGetResult(out var sale)) + return OperationResult.Bad(saleResult.Error); + + var updateResult = presentation!.UpdatePrice(cost!, sale!); + if (!updateResult.IsGood) + return OperationResult.Bad(updateResult.Error); + + await _unitOfWork.CommitAsync(cancellationToken); + return OperationResult.Good(ResultUnit.Value); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/UpdateProductPriceCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/UpdateProductPriceCommandHandler.cs index ac15663..cb1150d 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/UpdateProductPriceCommandHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Handlers/UpdateProductPriceCommandHandler.cs @@ -34,45 +34,10 @@ public UpdateProductPriceCommandHandler( _unitOfWork = unitOfWork; } - public async Task> Handle(UpdateProductPriceCommand request, CancellationToken cancellationToken) + public Task> Handle(UpdateProductPriceCommand request, CancellationToken cancellationToken) { - var tenantId = (Guid)_tenantProvider.TenantId; - - var productResult = await _productRepository.GetByIdAsync(request.ProductId, tenantId, cancellationToken); - if (!productResult.TryGetResult(out var product) || product is null) - { - return OperationResult.Bad(productResult.Error); - } - - var costResult = Money.FromDecimal(request.NewCostPrice); - if (!costResult.TryGetResult(out var costPrice) || costPrice is null) - { - return OperationResult.Bad(costResult.Error); - } - - var saleResult = Money.FromDecimal(request.NewSalePrice); - if (!saleResult.TryGetResult(out var salePrice) || salePrice is null) - { - return OperationResult.Bad(saleResult.Error); - } - - var updateResult = product.UpdatePrice(costPrice, salePrice); - if (!updateResult.IsGood) - { - return updateResult; - } - - var payload = new ProductPriceUpdatedPayload( - product.Id, - tenantId, - product.CostPrice, - product.SalePrice, - product.UpdatedAt); - - var outboxMessage = new OutboxMessage("ProductPriceUpdated", JsonSerializer.Serialize(payload)); - await _outboxRepository.AddAsync(outboxMessage, cancellationToken); - await _unitOfWork.CommitAsync(cancellationToken); - - return OperationResult.Good(ResultUnit.Value); + return Task.FromResult(OperationResult.Bad( + DomainError.Business("price.use_presentation_command", + "Prices are managed per ProductPresentation. Use AddProductPresentationCommand and set SalePrice/CostPrice there."))); } } diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetCatalogQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetCatalogQuery.cs index d8fa8c2..16f1a1c 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetCatalogQuery.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetCatalogQuery.cs @@ -4,15 +4,32 @@ namespace TuColmadoRD.Core.Application.Inventory.Queries; +public sealed record CatalogPresentationDto( + Guid Id, + Guid ProductId, + string DisplayName, + int PresentationType, + string PresentationTypeName, + int SellMode, + string SellModeName, + string? Brand, + decimal? NominalCapacity, + int MeasureUnit, + string MeasureUnitName, + decimal SalePrice, + decimal CostPrice, + bool IsActive, + int StockQuantity, + int OpenContainersCount, + int PackagedStockQuantity); + public sealed record CatalogItemDto( - Guid ProductId, - string Name, - Guid CategoryId, - string CategoryName, - decimal SalePrice, - decimal StockQuantity, - decimal ItbisRate, - int UnitTypeId, - bool IsActive); + Guid ProductId, + string Name, + Guid CategoryId, + string CategoryName, + decimal ItbisRate, + bool IsActive, + IReadOnlyList Presentations); public sealed record GetCatalogQuery() : IRequest, DomainError>>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetContainersByPresentationQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetContainersByPresentationQuery.cs new file mode 100644 index 0000000..6489427 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetContainersByPresentationQuery.cs @@ -0,0 +1,9 @@ +using MediatR; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public record GetContainersByPresentationQuery(Guid PresentationId) + : IRequest, DomainError>>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundTransactionsQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundTransactionsQuery.cs new file mode 100644 index 0000000..89c2193 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundTransactionsQuery.cs @@ -0,0 +1,29 @@ +using MediatR; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public sealed record FundTransactionPagedDto( + Guid Id, + Guid FundId, + int Type, + string TypeName, + decimal Amount, + int? Category, + string? CategoryName, + string Description, + string? JustificationNote, + Guid? ReferenceId, + decimal BalanceAfter, + DateTime OccurredAt); + +public sealed record FundTransactionsPagedResult( + IReadOnlyList Items, + int PageNumber, + int PageSize, + int TotalCount, + int TotalPages); + +public sealed record GetFundTransactionsQuery(Guid FundId, int Page = 1, int PageSize = 20) + : IRequest>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundsQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundsQuery.cs new file mode 100644 index 0000000..b384509 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetFundsQuery.cs @@ -0,0 +1,15 @@ +using MediatR; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public sealed record FundSummaryDto( + Guid Id, + Guid TenantId, + string Name, + decimal CurrentBalance, + DateTime CreatedAt); + +public sealed record GetFundsQuery + : IRequest, DomainError>>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetLowStockQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetLowStockQuery.cs index cc756bf..d974251 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetLowStockQuery.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetLowStockQuery.cs @@ -4,8 +4,8 @@ namespace TuColmadoRD.Core.Application.Inventory.Queries; -/// Response item for a product with critical stock level. -public sealed record LowStockItemDto(Guid ProductId, string Name, decimal StockQuantity, int Threshold); +/// Response item for a presentation with critical stock level. +public sealed record LowStockItemDto(Guid PresentationId, Guid ProductId, string ProductName, string PresentationDisplayName, int StockQuantity, int Threshold); /// Response wrapper for the low-stock endpoint. public sealed record LowStockResponse(int Count, IReadOnlyList Items); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetMonetaryFundQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetMonetaryFundQuery.cs new file mode 100644 index 0000000..b53882f --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetMonetaryFundQuery.cs @@ -0,0 +1,9 @@ +using MediatR; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public record GetMonetaryFundQuery(Guid FundId) + : IRequest>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetPresentationsByProductQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetPresentationsByProductQuery.cs new file mode 100644 index 0000000..751ade4 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetPresentationsByProductQuery.cs @@ -0,0 +1,9 @@ +using MediatR; +using TuColmadoRD.Core.Application.Inventory.DTOs; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public record GetPresentationsByProductQuery(Guid ProductId) + : IRequest, DomainError>>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetStockEntriesQuery.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetStockEntriesQuery.cs new file mode 100644 index 0000000..21bffe9 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Queries/GetStockEntriesQuery.cs @@ -0,0 +1,33 @@ +using MediatR; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Application.Inventory.Queries; + +public sealed record StockEntryLineResultDto( + Guid Id, + Guid StockEntryId, + Guid PresentationId, + string PresentationDisplayName, + int ContainerCount, + int UnitsPerContainer, + decimal NominalSizePerUnit, + decimal CostPerUnit, + decimal LineTotal); + +public sealed record StockEntryResultDto( + Guid Id, + DateTime PurchasedAt, + decimal TotalCost, + string? SupplierName, + string? Notes, + Guid? FundTransactionId, + IReadOnlyList Lines); + +public sealed record StockEntriesPagedResult( + IReadOnlyList Items, + int TotalCount, + int TotalPages); + +public sealed record GetStockEntriesQuery(int Page = 1, int PageSize = 20) + : IRequest>; diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Validators/CreateProductCommandValidator.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Validators/CreateProductCommandValidator.cs index 49a11a1..1ff683b 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Validators/CreateProductCommandValidator.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Inventory/Validators/CreateProductCommandValidator.cs @@ -17,16 +17,7 @@ public CreateProductCommandValidator() RuleFor(x => x.CategoryId) .NotEqual(Guid.Empty); - RuleFor(x => x.CostPrice) - .GreaterThanOrEqualTo(0); - - RuleFor(x => x.SalePrice) - .GreaterThanOrEqualTo(0); - RuleFor(x => x.ItbisRate) .InclusiveBetween(0, 1); - - RuleFor(x => x.UnitType) - .InclusiveBetween(1, 4); } } diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Purchasing/Handlers/PurchaseCompletedDomainEventHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Purchasing/Handlers/PurchaseCompletedDomainEventHandler.cs index 863b906..82b0bf7 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Purchasing/Handlers/PurchaseCompletedDomainEventHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Purchasing/Handlers/PurchaseCompletedDomainEventHandler.cs @@ -2,59 +2,26 @@ using MediatR; using TuColmadoRD.Core.Domain.Entities.Purchasing.Events; using TuColmadoRD.Core.Domain.Entities.System; -using TuColmadoRD.Core.Domain.Interfaces.Repositories.Inventory; using TuColmadoRD.Core.Domain.Interfaces.Repositories.Sales; using TuColmadoRD.Core.Domain.ValueObjects; -using TuColmadoRD.Core.Domain.ValueObjects.Base; namespace TuColmadoRD.Core.Application.Purchasing.Handlers; public sealed class PurchaseCompletedDomainEventHandler : INotificationHandler { - private readonly IProductRepository _productRepository; private readonly IShiftRepository _shiftRepository; private readonly TuColmadoRD.Core.Application.Inventory.Abstractions.IOutboxRepository _outboxRepository; public PurchaseCompletedDomainEventHandler( - IProductRepository productRepository, IShiftRepository shiftRepository, TuColmadoRD.Core.Application.Inventory.Abstractions.IOutboxRepository outboxRepository) { - _productRepository = productRepository; _shiftRepository = shiftRepository; _outboxRepository = outboxRepository; } public async Task Handle(PurchaseCompletedDomainEvent notification, CancellationToken cancellationToken) { - var productsToUpdate = new List(); - - foreach (var detail in notification.Details) - { - var product = await _productRepository.GetByIdAsync(detail.ProductId, null, cancellationToken); - if (product is not null) - { - var adjustedResult = product.AdjustStock(detail.Quantity); - - var moneyCostResult = Money.FromDecimal(detail.UnitCost); - if (moneyCostResult.TryGetResult(out var costPrice) && costPrice is not null) - { - product.UpdatePrice(costPrice, product.SalePrice); - } - - productsToUpdate.Add(product); - } - } - - if (productsToUpdate.Any()) - { - foreach (var p in productsToUpdate) - { - await ProcessDomainEventsAsync(p.DomainEvents, cancellationToken); - await _productRepository.UpdateAsync(p, cancellationToken); - } - } - var shift = await _shiftRepository.GetByIdAsync(notification.ShiftId, null, cancellationToken); if (shift is not null) { diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Commands/CreateSaleCommand.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Commands/CreateSaleCommand.cs index 281eb50..9dc3469 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Commands/CreateSaleCommand.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Commands/CreateSaleCommand.cs @@ -6,10 +6,11 @@ namespace TuColmadoRD.Core.Application.Sales.Commands; /// -/// Request item for creating a sale. +/// Request item for creating a sale. PresentationId identifies which form of the product is being sold. /// public sealed record SaleItemRequest( Guid ProductId, + Guid PresentationId, decimal Quantity); /// diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/CreateSaleCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/CreateSaleCommandHandler.cs index 8bd7477..8acad1f 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/CreateSaleCommandHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/CreateSaleCommandHandler.cs @@ -7,7 +7,9 @@ using TuColmadoRD.Core.Application.Sales.Outbox; using TuColmadoRD.Core.Domain.Base.Result; using TuColmadoRD.Core.Domain.Entities.Fiscal; +using TuColmadoRD.Core.Domain.Entities.Inventory; using TuColmadoRD.Core.Domain.Entities.Sales; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; using TuColmadoRD.Core.Domain.Interfaces.Repositories.Fiscal; using TuColmadoRD.Core.Domain.Interfaces.Repositories.System; using TuColmadoRD.Core.Application.Interfaces.Services; @@ -28,6 +30,9 @@ public sealed class CreateSaleCommandHandler : IRequestHandler> Handle( DomainError.NotFound("product.not_found", $"Producto {itemRequest.ProductId} no encontrado.")); } + var presentationDict = new Dictionary(); + foreach (var pId in request.Items.Select(i => i.PresentationId).Distinct()) + { + var pResult = await _presentationRepository.GetByIdAsync(pId, (Guid)tenantId, ct); + if (!pResult.TryGetResult(out var pres) || pres is null) + return OperationResult.Bad( + DomainError.NotFound("presentation.not_found", $"Presentación {pId} no encontrada.")); + presentationDict[pId] = pres!; + } + var quantitiesResult = ValidateAndPrepareQuantities(request.Items); if (!quantitiesResult.TryGetResult(out var quantities) || quantities is null) return OperationResult.Bad(quantitiesResult.Error); @@ -105,12 +126,29 @@ public async Task> Handle( for (int i = 0; i < request.Items.Count; i++) { var item = request.Items[i]; - var product = productDict[item.ProductId]; var qty = quantities[i]; + var presentation = presentationDict[item.PresentationId]; - var adjustResult = product.AdjustStock(-qty.Value); - if (!adjustResult.IsGood) - return OperationResult.Bad(adjustResult.Error); + if (presentation.PresentationType == PresentationType.PackagedUnit) + { + var packaged = await _packagedStockRepository.GetByPresentationIdAsync(item.PresentationId, (Guid)tenantId, ct); + if (packaged is null) + return OperationResult.Bad( + DomainError.NotFound("stock.packaged_not_found", $"Stock empacado no encontrado para presentación {item.PresentationId}.")); + var subtractResult = packaged.Subtract((int)qty.Value); + if (!subtractResult.IsGood) + return OperationResult.Bad(subtractResult.Error); + } + else + { + var container = await _containerRepository.GetActiveSourceAsync(item.PresentationId, (Guid)tenantId, ct); + if (container is null) + return OperationResult.Bad( + DomainError.NotFound("stock.no_active_container", $"No hay contenedor activo para presentación {item.PresentationId}.")); + var drawResult = container.Draw(qty.Value, allowOverDraw: false); + if (!drawResult.IsGood) + return OperationResult.Bad(drawResult.Error); + } } var receiptResult = await _sequenceService.GenerateReceiptNumberAsync(tenantId, terminalId, ct); @@ -126,13 +164,14 @@ public async Task> Handle( { var itemRequest = request.Items[i]; var product = productDict[itemRequest.ProductId]; + var presentation = presentationDict[itemRequest.PresentationId]; var qty = quantities[i]; var addItemResult = sale.AddItem( product.Id, product.Name, - product.SalePrice, - product.CostPrice, + presentation.SalePrice, + presentation.CostPrice, qty, product.ItbisRate); @@ -143,9 +182,9 @@ public async Task> Handle( product.Id, product.Name, qty.Value, - product.SalePrice.Amount, - (product.SalePrice.Amount * qty.Value * product.ItbisRate.Rate), - (product.SalePrice.Amount * qty.Value * (1 + product.ItbisRate.Rate)))); + presentation.SalePrice.Amount, + (presentation.SalePrice.Amount * qty.Value * product.ItbisRate.Rate), + (presentation.SalePrice.Amount * qty.Value * (1 + product.ItbisRate.Rate)))); } foreach (var paymentRequest in request.Payments) @@ -322,7 +361,6 @@ public async Task> Handle( // ──────────────────────────────────────────────────────────────────────── await _saleRepository.AddAsync(sale, ct); - await _productRepository.UpdateRangeAsync(products, ct); await _shiftRepository.UpdateAsync(shift, ct); await _outboxRepository.AddAsync(outboxMessage, ct); diff --git a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/VoidSaleCommandHandler.cs b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/VoidSaleCommandHandler.cs index 749d8d8..720777b 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/VoidSaleCommandHandler.cs +++ b/backend/src/core/TuColmadoRD.Core.Application/Modules/Sales/Handlers/VoidSaleCommandHandler.cs @@ -20,7 +20,6 @@ public sealed class VoidSaleCommandHandler : IRequestHandler> Handle( return OperationResult.Bad( DomainError.Business("sale.wrong_shift", "Solo puedes anular ventas del turno actual.")); - var productIds = sale.Items.Select(i => i.ProductId).Distinct().ToList(); - var products = await _productRepository.GetByIdsAsync(productIds, tenantId, ct); - var productDict = products.ToDictionary(p => p.Id); - - foreach (var saleItem in sale.Items) - { - var product = productDict[saleItem.ProductId]; - var adjustResult = product.AdjustStock(saleItem.QuantityValue); - if (!adjustResult.IsGood) - return OperationResult.Bad(adjustResult.Error); - } - var voidResult = sale.Void(request.VoidReason); if (!voidResult.IsGood) return OperationResult.Bad(voidResult.Error); @@ -103,7 +88,6 @@ public async Task> Handle( var outboxMessage = new OutboxMessage("SaleVoided", JsonSerializer.Serialize(saleVoidedPayload)); await _saleRepository.UpdateAsync(sale, ct); - await _productRepository.UpdateRangeAsync(products, ct); await _shiftRepository.UpdateAsync(shift, ct); await _outboxRepository.AddAsync(outboxMessage, ct); await _unitOfWork.CommitAsync(ct); diff --git a/backend/src/core/TuColmadoRD.Core.Application/TuColmadoRD.Core.Application.csproj b/backend/src/core/TuColmadoRD.Core.Application/TuColmadoRD.Core.Application.csproj index 35b1239..6c23f01 100644 --- a/backend/src/core/TuColmadoRD.Core.Application/TuColmadoRD.Core.Application.csproj +++ b/backend/src/core/TuColmadoRD.Core.Application/TuColmadoRD.Core.Application.csproj @@ -9,7 +9,9 @@ - + + + diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/ContainerStatusChangedDomainEvent.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/ContainerStatusChangedDomainEvent.cs new file mode 100644 index 0000000..2f0f614 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/ContainerStatusChangedDomainEvent.cs @@ -0,0 +1,10 @@ +using TuColmadoRD.Core.Domain.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory.Events; + +public sealed record ContainerStatusChangedDomainEvent( + Guid ContainerId, + Guid PresentationId, + Guid TenantId, + string NewStatus, + DateTime OccurredAt) : IDomainEvent; diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/FundTransactionRecordedDomainEvent.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/FundTransactionRecordedDomainEvent.cs new file mode 100644 index 0000000..9f15141 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/FundTransactionRecordedDomainEvent.cs @@ -0,0 +1,12 @@ +using TuColmadoRD.Core.Domain.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory.Events; + +public sealed record FundTransactionRecordedDomainEvent( + Guid TransactionId, + Guid FundId, + Guid TenantId, + string TransactionType, + decimal Amount, + decimal BalanceAfter, + DateTime OccurredAt) : IDomainEvent; diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/PresentationCreatedDomainEvent.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/PresentationCreatedDomainEvent.cs new file mode 100644 index 0000000..8e9a1de --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/PresentationCreatedDomainEvent.cs @@ -0,0 +1,10 @@ +using TuColmadoRD.Core.Domain.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory.Events; + +public sealed record PresentationCreatedDomainEvent( + Guid PresentationId, + Guid ProductId, + Guid TenantId, + string DisplayName, + DateTime OccurredAt) : IDomainEvent; diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/StockEntryConfirmedDomainEvent.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/StockEntryConfirmedDomainEvent.cs new file mode 100644 index 0000000..fb6783d --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Events/StockEntryConfirmedDomainEvent.cs @@ -0,0 +1,10 @@ +using TuColmadoRD.Core.Domain.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory.Events; + +public sealed record StockEntryConfirmedDomainEvent( + Guid StockEntryId, + Guid TenantId, + decimal TotalCost, + int LineCount, + DateTime OccurredAt) : IDomainEvent; diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/MonetaryFund.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/MonetaryFund.cs new file mode 100644 index 0000000..52500d6 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/MonetaryFund.cs @@ -0,0 +1,192 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory.Events; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory; + +/// +/// Capital fund the colmado uses for purchasing stock. +/// Not the same as the cash register — this is reserved purchasing capital. +/// +public class MonetaryFund : ITenantEntity +{ + private readonly List _transactions = []; + private readonly List _domainEvents = []; + + private MonetaryFund() + { + TenantId = TenantIdentifier.Empty; + Name = string.Empty; + CurrentBalance = Money.Zero; + } + + private MonetaryFund(Guid tenantId, string name, Money initialDeposit) + { + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + Name = name.Trim(); + CurrentBalance = initialDeposit; + CreatedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + + var tx = FundTransaction.CreateDeposit(Id, tenantId, initialDeposit, "Depósito inicial", initialDeposit); + _transactions.Add(tx); + AddDomainEvent(new FundTransactionRecordedDomainEvent( + tx.Id, Id, tenantId, FundTransactionType.Deposit.Name, + initialDeposit.Amount, CurrentBalance.Amount, DateTime.UtcNow)); + } + + public Guid Id { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public string Name { get; private set; } + public Money CurrentBalance { get; private set; } + public DateTime CreatedAt { get; private set; } + public DateTime UpdatedAt { get; private set; } + + public IReadOnlyCollection Transactions => _transactions.AsReadOnly(); + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + + public static OperationResult Create( + Guid tenantId, + string name, + Money initialDeposit) + { + if (tenantId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("fund.tenant_required")); + + if (string.IsNullOrWhiteSpace(name)) + return OperationResult.Bad(DomainError.Validation("fund.name_required")); + + if (name.Length > 80) + return OperationResult.Bad(DomainError.Validation("fund.name_too_long")); + + if (initialDeposit.Amount < 0) + return OperationResult.Bad(DomainError.Validation("fund.initial_deposit_cannot_be_negative")); + + return OperationResult.Good(new MonetaryFund(tenantId, name, initialDeposit)); + } + + public OperationResult Deposit(Money amount, string description) + { + if (amount.Amount <= 0) + return OperationResult.Bad(DomainError.Validation("fund.deposit_amount_must_be_positive")); + + CurrentBalance = CurrentBalance + amount; + UpdatedAt = DateTime.UtcNow; + + var tx = FundTransaction.CreateDeposit(Id, TenantId.Value, amount, description, CurrentBalance); + _transactions.Add(tx); + AddDomainEvent(new FundTransactionRecordedDomainEvent( + tx.Id, Id, TenantId.Value, FundTransactionType.Deposit.Name, + amount.Amount, CurrentBalance.Amount, DateTime.UtcNow)); + + return OperationResult.Good(tx); + } + + /// + /// Records an expense against the fund. + /// When amount exceeds balance, justificationNote is mandatory. + /// + public OperationResult RecordExpense( + Money amount, + FundExpenseCategory category, + string description, + string? justificationNote, + Guid? referenceId = null) + { + if (amount.Amount <= 0) + return OperationResult.Bad(DomainError.Validation("fund.expense_amount_must_be_positive")); + + bool exceedsBalance = amount.Amount > CurrentBalance.Amount; + + if (exceedsBalance && string.IsNullOrWhiteSpace(justificationNote)) + return OperationResult.Bad( + DomainError.Business("fund.justification_required_when_exceeding_balance")); + + // Allow overdraft — record the actual balance (can go negative) + var balanceAfterResult = Money.FromDecimal(CurrentBalance.Amount - amount.Amount); + if (!balanceAfterResult.TryGetResult(out var balanceAfter)) + { + // Balance would go negative — create a zero-floor Money via direct subtraction workaround + balanceAfter = Money.Zero; + } + + // When overdrafting, store negative balance as zero (tracked via justification) + CurrentBalance = exceedsBalance ? Money.Zero : balanceAfter!; + UpdatedAt = DateTime.UtcNow; + + var tx = FundTransaction.CreateExpense( + Id, TenantId.Value, amount, category, description, + justificationNote, referenceId, CurrentBalance); + _transactions.Add(tx); + AddDomainEvent(new FundTransactionRecordedDomainEvent( + tx.Id, Id, TenantId.Value, FundTransactionType.Expense.Name, + amount.Amount, CurrentBalance.Amount, DateTime.UtcNow)); + + return OperationResult.Good(tx); + } + + public void ClearDomainEvents() => _domainEvents.Clear(); + private void AddDomainEvent(object @event) => _domainEvents.Add(@event); +} + +public class FundTransaction +{ + private FundTransaction() + { + TenantId = TenantIdentifier.Empty; + Description = string.Empty; + Type = FundTransactionType.Deposit; + Amount = Money.Zero; + BalanceAfter = Money.Zero; + } + + private FundTransaction( + Guid fundId, + Guid tenantId, + FundTransactionType type, + Money amount, + FundExpenseCategory? category, + string description, + string? justificationNote, + Guid? referenceId, + Money balanceAfter) + { + Id = Guid.NewGuid(); + FundId = fundId; + TenantId = TenantIdentifier.Validate(tenantId).Result; + Type = type; + Amount = amount; + Category = category; + Description = description; + JustificationNote = justificationNote; + ReferenceId = referenceId; + BalanceAfter = balanceAfter; + OccurredAt = DateTime.UtcNow; + } + + public Guid Id { get; private set; } + public Guid FundId { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public FundTransactionType Type { get; private set; } + public Money Amount { get; private set; } + public FundExpenseCategory? Category { get; private set; } + public string Description { get; private set; } + public string? JustificationNote { get; private set; } + public Guid? ReferenceId { get; private set; } + public Money BalanceAfter { get; private set; } + public DateTime OccurredAt { get; private set; } + + internal static FundTransaction CreateDeposit( + Guid fundId, Guid tenantId, Money amount, string description, Money balanceAfter) => + new(fundId, tenantId, FundTransactionType.Deposit, amount, null, description, null, null, balanceAfter); + + internal static FundTransaction CreateExpense( + Guid fundId, Guid tenantId, Money amount, FundExpenseCategory category, + string description, string? justificationNote, Guid? referenceId, Money balanceAfter) => + new(fundId, tenantId, FundTransactionType.Expense, amount, category, + description, justificationNote, referenceId, balanceAfter); +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/PackagedStock.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/PackagedStock.cs new file mode 100644 index 0000000..791bb13 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/PackagedStock.cs @@ -0,0 +1,67 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory; + +/// +/// Simple unit counter for packaged presentations (bags, bottles, packets). +/// One record per presentation — quantity incremented on stock entry, decremented on sale. +/// +public class PackagedStock : ITenantEntity +{ + private PackagedStock() + { + TenantId = TenantIdentifier.Empty; + } + + private PackagedStock(Guid tenantId, Guid presentationId) + { + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + PresentationId = presentationId; + Quantity = 0; + LastUpdatedAt = DateTime.UtcNow; + } + + public Guid Id { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public Guid PresentationId { get; private set; } + public int Quantity { get; private set; } + public DateTime LastUpdatedAt { get; private set; } + + public static OperationResult Create(Guid tenantId, Guid presentationId) + { + if (tenantId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("packaged_stock.tenant_required")); + + if (presentationId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("packaged_stock.presentation_required")); + + return OperationResult.Good(new PackagedStock(tenantId, presentationId)); + } + + public OperationResult Add(int units) + { + if (units <= 0) + return OperationResult.Bad(DomainError.Validation("packaged_stock.units_must_be_positive")); + + Quantity += units; + LastUpdatedAt = DateTime.UtcNow; + return OperationResult.Good(Unit.Value); + } + + public OperationResult Subtract(int units) + { + if (units <= 0) + return OperationResult.Bad(DomainError.Validation("packaged_stock.units_must_be_positive")); + + if (units > Quantity) + return OperationResult.Bad(DomainError.Business("packaged_stock.insufficient_quantity")); + + Quantity -= units; + LastUpdatedAt = DateTime.UtcNow; + return OperationResult.Good(Unit.Value); + } +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Product.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Product.cs index 16a4b2e..c413582 100644 --- a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Product.cs +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/Product.cs @@ -1,269 +1,112 @@ using TuColmadoRD.Core.Domain.Base; using TuColmadoRD.Core.Domain.Base.Result; using TuColmadoRD.Core.Domain.Entities.Inventory.Events; -using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; using TuColmadoRD.Core.Domain.ValueObjects; using TuColmadoRD.Core.Domain.ValueObjects.Base; namespace TuColmadoRD.Core.Domain.Entities.Inventory; -/// -/// Product aggregate root for inventory operations. -/// public class Product : ITenantEntity { private readonly List _domainEvents = []; + private readonly List _presentations = []; private Product() { - Name = string.Empty; + Name = string.Empty; TenantId = TenantIdentifier.Empty; - CostPrice = Money.Zero; - SalePrice = Money.Zero; - ItbisRate = TaxRate.Zero; - UnitType = UnitType.Unit; } - private Product( - Guid tenantId, - string name, - Guid categoryId, - Money costPrice, - Money salePrice, - TaxRate itbisRate, - UnitType unitType) + private Product(Guid tenantId, string name, Guid categoryId, TaxRate itbisRate) { - Id = Guid.NewGuid(); - TenantId = TenantIdentifier.Validate(tenantId).Result; - Name = name; + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + Name = name; CategoryId = categoryId; - CostPrice = costPrice; - SalePrice = salePrice; ItbisRate = itbisRate; - UnitType = unitType; - IsActive = true; + IsActive = true; CreatedAt = DateTime.UtcNow; UpdatedAt = DateTime.UtcNow; - StockQuantity = 0m; AddDomainEvent(new ProductCreatedDomainEvent(Id, tenantId, Name, DateTime.UtcNow)); } - /// - /// Product identifier. - /// - public Guid Id { get; private set; } + private Product(Guid productId, Guid tenantId, string name, Guid categoryId, TaxRate itbisRate) + { + Id = productId; + TenantId = TenantIdentifier.Validate(tenantId).Result; + Name = name; + CategoryId = categoryId; + ItbisRate = itbisRate; + IsActive = true; + CreatedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + } - /// - /// Tenant identifier. - /// + public Guid Id { get; private set; } public TenantIdentifier TenantId { get; private set; } + public string Name { get; private set; } + public Guid CategoryId { get; private set; } + public TaxRate ItbisRate { get; private set; } + public bool IsActive { get; private set; } + public DateTime CreatedAt { get; private set; } + public DateTime UpdatedAt { get; private set; } - /// - /// Product name. - /// - public string Name { get; private set; } - - /// - /// Category identifier. - /// - public Guid CategoryId { get; private set; } - - /// - /// Cost price. - /// - public Money CostPrice { get; private set; } - - /// - /// Sale price. - /// - public Money SalePrice { get; private set; } + public IReadOnlyCollection Presentations => _presentations.AsReadOnly(); + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); - /// - /// ITBIS tax rate. - /// - public TaxRate ItbisRate { get; private set; } - - /// - /// Unit type. - /// - public UnitType UnitType { get; private set; } - - /// - /// Indicates if product is active. - /// - public bool IsActive { get; private set; } - - /// - /// Creation timestamp (UTC). - /// - public DateTime CreatedAt { get; private set; } - - /// - /// Last update timestamp (UTC). - /// - public DateTime UpdatedAt { get; private set; } - - /// - /// Current stock quantity. - /// - public decimal StockQuantity { get; private set; } - - /// - /// Buffered domain events emitted by this aggregate. - /// - public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); - - /// - /// Creates a new product aggregate. - /// public static OperationResult Create( Guid tenantId, string name, Guid categoryId, - Money costPrice, - Money salePrice, - TaxRate itbisRate, - UnitType unitType) + TaxRate itbisRate) { if (tenantId == Guid.Empty) - { return OperationResult.Bad(DomainError.Validation("product.tenant_required")); - } if (string.IsNullOrWhiteSpace(name)) - { return OperationResult.Bad(DomainError.Validation("product.name_required")); - } if (name.Length > 120) - { return OperationResult.Bad(DomainError.Validation("product.name_too_long")); - } if (categoryId == Guid.Empty) - { return OperationResult.Bad(DomainError.Validation("product.category_required")); - } - - if (salePrice.Amount < costPrice.Amount) - { - return OperationResult.Bad(DomainError.Validation("product.sale_price_below_cost")); - } - return OperationResult.Good( - new Product(tenantId, name.Trim(), categoryId, costPrice, salePrice, itbisRate, unitType)); + return OperationResult.Good(new Product(tenantId, name.Trim(), categoryId, itbisRate)); } - /// - /// Rehydrates product for catalog sync insert flow. - /// - public static OperationResult RehydrateForCatalogSync( - Guid productId, - Guid tenantId, - Guid categoryId, - string name, - Money costPrice, - Money salePrice, - TaxRate itbisRate) - { - var createResult = Create(tenantId, name, categoryId, costPrice, salePrice, itbisRate, UnitType.Unit); - if (!createResult.TryGetResult(out var product) || product is null) - { - return OperationResult.Bad(createResult.Error); - } - - product.Id = productId; - product.CreatedAt = DateTime.UtcNow; - product.UpdatedAt = DateTime.UtcNow; - product.ClearDomainEvents(); - - return OperationResult.Good(product); - } - - /// - /// Updates product prices. - /// - public OperationResult UpdatePrice(Money newCostPrice, Money newSalePrice) - { - if (newSalePrice.Amount < newCostPrice.Amount) - { - return OperationResult.Bad(DomainError.Validation("product.sale_price_below_cost")); - } - - CostPrice = newCostPrice; - SalePrice = newSalePrice; - UpdatedAt = DateTime.UtcNow; - AddDomainEvent(new ProductPriceUpdatedDomainEvent(Id, TenantId, SalePrice, DateTime.UtcNow)); - - return OperationResult.Good(Unit.Value); - } + /// Reconstructs a product from an external catalog, preserving the remote ID. + public static Product Rehydrate(Guid productId, Guid tenantId, string name, Guid categoryId, TaxRate itbisRate) => + new Product(productId, tenantId, name.Trim(), categoryId, itbisRate); - /// - /// Updates basic fields from catalog synchronization payload. - /// - public OperationResult UpdateFromCatalogSync( - Guid categoryId, - string name, - Money costPrice, - Money salePrice) + public OperationResult UpdateName(string name) { if (string.IsNullOrWhiteSpace(name)) - { return OperationResult.Bad(DomainError.Validation("product.name_required")); - } if (name.Length > 120) - { return OperationResult.Bad(DomainError.Validation("product.name_too_long")); - } - - if (salePrice.Amount < costPrice.Amount) - { - return OperationResult.Bad(DomainError.Validation("product.sale_price_below_cost")); - } - CategoryId = categoryId; - Name = name.Trim(); - CostPrice = costPrice; - SalePrice = salePrice; + Name = name.Trim(); UpdatedAt = DateTime.UtcNow; - return OperationResult.Good(Unit.Value); } - /// - /// Adjusts stock by delta quantity. - /// - public OperationResult AdjustStock(decimal delta) + public OperationResult UpdateItbisRate(TaxRate itbisRate) { - var newStock = StockQuantity + delta; - if (newStock < 0) - { - return OperationResult.Bad(DomainError.Business("product.insufficient_stock")); - } - - StockQuantity = newStock; + ItbisRate = itbisRate; UpdatedAt = DateTime.UtcNow; - AddDomainEvent(new StockAdjustedDomainEvent(Id, TenantId, delta, StockQuantity, DateTime.UtcNow)); - return OperationResult.Good(Unit.Value); } - /// - /// Deactivates product. - /// public void Deactivate() { - IsActive = false; + IsActive = false; UpdatedAt = DateTime.UtcNow; AddDomainEvent(new ProductDeactivatedDomainEvent(Id, TenantId, DateTime.UtcNow)); } - /// - /// Clears pending aggregate domain events. - /// public void ClearDomainEvents() => _domainEvents.Clear(); - private void AddDomainEvent(object @event) => _domainEvents.Add(@event); } diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/ProductPresentation.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/ProductPresentation.cs new file mode 100644 index 0000000..f9253e3 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/ProductPresentation.cs @@ -0,0 +1,130 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory.Events; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory; + +public class ProductPresentation : ITenantEntity +{ + private readonly List _domainEvents = []; + + private ProductPresentation() + { + TenantId = TenantIdentifier.Empty; + DisplayName = string.Empty; + Brand = string.Empty; + PresentationType = PresentationType.PackagedUnit; + SellMode = SellMode.ByUnit; + MeasureUnit = UnitOfMeasure.Unit; + SalePrice = Money.Zero; + CostPrice = Money.Zero; + } + + private ProductPresentation( + Guid tenantId, + Guid productId, + string displayName, + PresentationType presentationType, + SellMode sellMode, + UnitOfMeasure measureUnit, + Money salePrice, + Money costPrice, + string? brand, + decimal? nominalCapacity) + { + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + ProductId = productId; + DisplayName = displayName.Trim(); + PresentationType = presentationType; + SellMode = sellMode; + MeasureUnit = measureUnit; + SalePrice = salePrice; + CostPrice = costPrice; + Brand = brand?.Trim() ?? string.Empty; + NominalCapacity = nominalCapacity; + IsActive = true; + CreatedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + + AddDomainEvent(new PresentationCreatedDomainEvent(Id, productId, tenantId, DisplayName, DateTime.UtcNow)); + } + + public Guid Id { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public Guid ProductId { get; private set; } + public string DisplayName { get; private set; } + public PresentationType PresentationType { get; private set; } + public SellMode SellMode { get; private set; } + public UnitOfMeasure MeasureUnit { get; private set; } + public Money SalePrice { get; private set; } + public Money CostPrice { get; private set; } + public string Brand { get; private set; } + + /// Declared capacity per container (e.g. 50 for a 50-lb sack). Null for packaged units. + public decimal? NominalCapacity { get; private set; } + + public bool IsActive { get; private set; } + public DateTime CreatedAt { get; private set; } + public DateTime UpdatedAt { get; private set; } + + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + + public static OperationResult Create( + Guid tenantId, + Guid productId, + string displayName, + PresentationType presentationType, + SellMode sellMode, + UnitOfMeasure measureUnit, + Money salePrice, + Money costPrice, + string? brand, + decimal? nominalCapacity) + { + if (tenantId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("presentation.tenant_required")); + + if (productId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("presentation.product_required")); + + if (string.IsNullOrWhiteSpace(displayName)) + return OperationResult.Bad(DomainError.Validation("presentation.display_name_required")); + + if (displayName.Length > 100) + return OperationResult.Bad(DomainError.Validation("presentation.display_name_too_long")); + + if (salePrice.Amount < costPrice.Amount) + return OperationResult.Bad(DomainError.Validation("presentation.sale_price_below_cost")); + + if (presentationType == PresentationType.BulkContainer && (nominalCapacity is null || nominalCapacity <= 0)) + return OperationResult.Bad(DomainError.Validation("presentation.bulk_requires_nominal_capacity")); + + return OperationResult.Good(new ProductPresentation( + tenantId, productId, displayName, presentationType, sellMode, + measureUnit, salePrice, costPrice, brand, nominalCapacity)); + } + + public OperationResult UpdatePrice(Money newCostPrice, Money newSalePrice) + { + if (newSalePrice.Amount < newCostPrice.Amount) + return OperationResult.Bad(DomainError.Validation("presentation.sale_price_below_cost")); + + CostPrice = newCostPrice; + SalePrice = newSalePrice; + UpdatedAt = DateTime.UtcNow; + return OperationResult.Good(Unit.Value); + } + + public void Deactivate() + { + IsActive = false; + UpdatedAt = DateTime.UtcNow; + } + + public void ClearDomainEvents() => _domainEvents.Clear(); + private void AddDomainEvent(object @event) => _domainEvents.Add(@event); +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockContainer.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockContainer.cs new file mode 100644 index 0000000..28f5b0d --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockContainer.cs @@ -0,0 +1,175 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory.Events; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory; + +/// +/// Tracks an individual bulk container (sack, jar, bar). +/// One StockContainer = one physical sack/container purchased. +/// +public class StockContainer : ITenantEntity +{ + private readonly List _domainEvents = []; + + private StockContainer() + { + TenantId = TenantIdentifier.Empty; + ContainerCode = string.Empty; + Status = ContainerStatus.Sealed; + Notes = string.Empty; + } + + private StockContainer( + Guid tenantId, + Guid presentationId, + string containerCode, + decimal nominalCapacity, + decimal? actualCapacity, + DateTime purchasedAt, + string? notes) + { + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + PresentationId = presentationId; + ContainerCode = containerCode; + NominalCapacity = nominalCapacity; + ActualCapacity = actualCapacity; + CurrentRemaining = actualCapacity ?? nominalCapacity; + Status = ContainerStatus.Sealed; + IsActiveSource = false; + Notes = notes?.Trim() ?? string.Empty; + PurchasedAt = purchasedAt; + CreatedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + } + + public Guid Id { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public Guid PresentationId { get; private set; } + public string ContainerCode { get; private set; } + + /// Declared capacity (e.g. 50 lbs as written on the sack). + public decimal NominalCapacity { get; private set; } + + /// Real weighed capacity — may differ from nominal. Null if not weighed. + public decimal? ActualCapacity { get; private set; } + + /// How much product remains in this container. + public decimal CurrentRemaining { get; private set; } + + public ContainerStatus Status { get; private set; } + + /// True when this is the container currently being served from. + public bool IsActiveSource { get; private set; } + + public string Notes { get; private set; } + public DateTime PurchasedAt { get; private set; } + public DateTime? OpenedAt { get; private set; } + public DateTime? EmptiedAt { get; private set; } + public DateTime CreatedAt { get; private set; } + public DateTime UpdatedAt { get; private set; } + + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + + public static OperationResult Create( + Guid tenantId, + Guid presentationId, + string containerCode, + decimal nominalCapacity, + decimal? actualCapacity, + DateTime purchasedAt, + string? notes) + { + if (tenantId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("container.tenant_required")); + + if (presentationId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("container.presentation_required")); + + if (string.IsNullOrWhiteSpace(containerCode)) + return OperationResult.Bad(DomainError.Validation("container.code_required")); + + if (nominalCapacity <= 0) + return OperationResult.Bad(DomainError.Validation("container.nominal_capacity_must_be_positive")); + + if (actualCapacity is not null && actualCapacity <= 0) + return OperationResult.Bad(DomainError.Validation("container.actual_capacity_must_be_positive")); + + return OperationResult.Good(new StockContainer( + tenantId, presentationId, containerCode, nominalCapacity, actualCapacity, purchasedAt, notes)); + } + + /// Registers the real weighed capacity (can differ from nominal). + public OperationResult SetActualCapacity(decimal actual) + { + if (actual <= 0) + return OperationResult.Bad(DomainError.Validation("container.actual_capacity_must_be_positive")); + + ActualCapacity = actual; + CurrentRemaining = actual; + UpdatedAt = DateTime.UtcNow; + return OperationResult.Good(Unit.Value); + } + + /// Opens the container so product can be drawn from it. + public OperationResult Open() + { + if (Status != ContainerStatus.Sealed) + return OperationResult.Bad(DomainError.Business("container.must_be_sealed_to_open")); + + Status = ContainerStatus.Open; + OpenedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + AddDomainEvent(new ContainerStatusChangedDomainEvent(Id, PresentationId, TenantId.Value, Status.Name, DateTime.UtcNow)); + return OperationResult.Good(Unit.Value); + } + + /// + /// Draws a quantity from this container. + /// When allowOverDraw is true the draw is accepted even if it exceeds remaining + /// (models weight variation — a sack might have slightly more than declared). + /// + public OperationResult Draw(decimal amount, bool allowOverDraw = false) + { + if (Status != ContainerStatus.Open) + return OperationResult.Bad(DomainError.Business("container.must_be_open_to_draw")); + + if (amount <= 0) + return OperationResult.Bad(DomainError.Validation("container.draw_amount_must_be_positive")); + + if (!allowOverDraw && amount > CurrentRemaining) + return OperationResult.Bad(DomainError.Business("container.insufficient_remaining")); + + CurrentRemaining -= amount; + UpdatedAt = DateTime.UtcNow; + return OperationResult.Good(Unit.Value); + } + + /// Marks the container as empty (fully consumed). + public OperationResult MarkEmpty() + { + if (Status == ContainerStatus.Empty) + return OperationResult.Bad(DomainError.Business("container.already_empty")); + + Status = ContainerStatus.Empty; + IsActiveSource = false; + EmptiedAt = DateTime.UtcNow; + UpdatedAt = DateTime.UtcNow; + AddDomainEvent(new ContainerStatusChangedDomainEvent(Id, PresentationId, TenantId.Value, Status.Name, DateTime.UtcNow)); + return OperationResult.Good(Unit.Value); + } + + /// Flags this container as the active source to draw from. + public void SetAsActiveSource(bool active) + { + IsActiveSource = active; + UpdatedAt = DateTime.UtcNow; + } + + public void ClearDomainEvents() => _domainEvents.Clear(); + private void AddDomainEvent(object @event) => _domainEvents.Add(@event); +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockEntry.cs b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockEntry.cs new file mode 100644 index 0000000..fcd1800 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Entities/Inventory/StockEntry.cs @@ -0,0 +1,146 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory.Events; +using TuColmadoRD.Core.Domain.ValueObjects; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Entities.Inventory; + +/// +/// A purchase event that can contain multiple lines of different presentations. +/// Example: "4 boxes × 50 units of 1-lb bags + 2 sacks × 50 lb bulk rice". +/// +public class StockEntry : ITenantEntity +{ + private readonly List _lines = []; + private readonly List _domainEvents = []; + + private StockEntry() + { + TenantId = TenantIdentifier.Empty; + SupplierName = string.Empty; + Notes = string.Empty; + TotalCost = Money.Zero; + } + + private StockEntry(Guid tenantId, DateTime purchasedAt, string? supplierName, string? notes) + { + Id = Guid.NewGuid(); + TenantId = TenantIdentifier.Validate(tenantId).Result; + PurchasedAt = purchasedAt; + SupplierName = supplierName?.Trim() ?? string.Empty; + Notes = notes?.Trim() ?? string.Empty; + TotalCost = Money.Zero; + CreatedAt = DateTime.UtcNow; + } + + public Guid Id { get; private set; } + public TenantIdentifier TenantId { get; private set; } + public DateTime PurchasedAt { get; private set; } + public string SupplierName { get; private set; } + public string Notes { get; private set; } + public Money TotalCost { get; private set; } + public Guid? FundTransactionId { get; private set; } + public DateTime CreatedAt { get; private set; } + + public IReadOnlyCollection Lines => _lines.AsReadOnly(); + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + + public static OperationResult Create( + Guid tenantId, + DateTime purchasedAt, + string? supplierName, + string? notes) + { + if (tenantId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("stock_entry.tenant_required")); + + return OperationResult.Good(new StockEntry(tenantId, purchasedAt, supplierName, notes)); + } + + public OperationResult AddLine( + Guid presentationId, + int containerCount, + int unitsPerContainer, + decimal nominalSizePerUnit, + Money costPerUnit) + { + if (presentationId == Guid.Empty) + return OperationResult.Bad(DomainError.Validation("stock_entry_line.presentation_required")); + + if (containerCount <= 0) + return OperationResult.Bad(DomainError.Validation("stock_entry_line.container_count_must_be_positive")); + + if (unitsPerContainer <= 0) + return OperationResult.Bad(DomainError.Validation("stock_entry_line.units_per_container_must_be_positive")); + + if (nominalSizePerUnit <= 0) + return OperationResult.Bad(DomainError.Validation("stock_entry_line.nominal_size_must_be_positive")); + + var line = new StockEntryLine(Id, presentationId, containerCount, unitsPerContainer, nominalSizePerUnit, costPerUnit); + _lines.Add(line); + + var lineTotal = costPerUnit.Amount * containerCount * unitsPerContainer; + TotalCost = TotalCost + Money.FromDecimal(lineTotal).Result; + + return OperationResult.Good(Unit.Value); + } + + public OperationResult Confirm() + { + if (_lines.Count == 0) + return OperationResult.Bad(DomainError.Business("stock_entry.must_have_at_least_one_line")); + + AddDomainEvent(new StockEntryConfirmedDomainEvent(Id, TenantId.Value, TotalCost.Amount, _lines.Count, DateTime.UtcNow)); + return OperationResult.Good(Unit.Value); + } + + public void LinkFundTransaction(Guid fundTransactionId) + { + FundTransactionId = fundTransactionId; + } + + public void ClearDomainEvents() => _domainEvents.Clear(); + private void AddDomainEvent(object @event) => _domainEvents.Add(@event); +} + +public class StockEntryLine +{ + internal StockEntryLine( + Guid stockEntryId, + Guid presentationId, + int containerCount, + int unitsPerContainer, + decimal nominalSizePerUnit, + Money costPerUnit) + { + Id = Guid.NewGuid(); + StockEntryId = stockEntryId; + PresentationId = presentationId; + ContainerCount = containerCount; + UnitsPerContainer = unitsPerContainer; + NominalSizePerUnit = nominalSizePerUnit; + CostPerUnit = costPerUnit; + } + + // EF Core needs a parameterless ctor + private StockEntryLine() { CostPerUnit = Money.Zero; } + + public Guid Id { get; private set; } + public Guid StockEntryId { get; private set; } + public Guid PresentationId { get; private set; } + + /// Number of boxes / sacks purchased. + public int ContainerCount { get; private set; } + + /// Units inside each box (1 for bulk sacks). + public int UnitsPerContainer { get; private set; } + + /// Declared weight/volume per unit (e.g. 1 lb per bag). + public decimal NominalSizePerUnit { get; private set; } + + public Money CostPerUnit { get; private set; } + + public int TotalUnits => ContainerCount * UnitsPerContainer; + public decimal TotalNominalWeight => TotalUnits * NominalSizePerUnit; +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/ContainerStatus.cs b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/ContainerStatus.cs new file mode 100644 index 0000000..5c33478 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/ContainerStatus.cs @@ -0,0 +1,36 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +public sealed class ContainerStatus : Enumeration +{ + /// Container received but not yet opened. + public static readonly ContainerStatus Sealed = new(1, nameof(Sealed)); + + /// Container is open and being drawn from. + public static readonly ContainerStatus Open = new(2, nameof(Open)); + + /// Container is fully consumed. + public static readonly ContainerStatus Empty = new(3, nameof(Empty)); + + private ContainerStatus(int id, string name) : base(id, name) { } + + public static OperationResult FromId(int id) + { + var result = id switch + { + 1 => Sealed, + 2 => Open, + 3 => Empty, + _ => null + }; + + return result is null + ? OperationResult.Bad(DomainError.Validation("container_status.unknown_id")) + : OperationResult.Good(result); + } + + public static implicit operator int(ContainerStatus s) => s.Id; +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundExpenseCategory.cs b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundExpenseCategory.cs new file mode 100644 index 0000000..5c433a2 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundExpenseCategory.cs @@ -0,0 +1,35 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +public sealed class FundExpenseCategory : Enumeration +{ + public static readonly FundExpenseCategory StockPurchase = new(1, nameof(StockPurchase)); + public static readonly FundExpenseCategory Operational = new(2, nameof(Operational)); + public static readonly FundExpenseCategory Loss = new(3, nameof(Loss)); + public static readonly FundExpenseCategory ExternalFund = new(4, nameof(ExternalFund)); + public static readonly FundExpenseCategory Other = new(5, nameof(Other)); + + private FundExpenseCategory(int id, string name) : base(id, name) { } + + public static OperationResult FromId(int id) + { + var result = id switch + { + 1 => StockPurchase, + 2 => Operational, + 3 => Loss, + 4 => ExternalFund, + 5 => Other, + _ => null + }; + + return result is null + ? OperationResult.Bad(DomainError.Validation("fund_expense_category.unknown_id")) + : OperationResult.Good(result); + } + + public static implicit operator int(FundExpenseCategory c) => c.Id; +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundTransactionType.cs b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundTransactionType.cs new file mode 100644 index 0000000..3c70c24 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/FundTransactionType.cs @@ -0,0 +1,29 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +public sealed class FundTransactionType : Enumeration +{ + public static readonly FundTransactionType Deposit = new(1, nameof(Deposit)); + public static readonly FundTransactionType Expense = new(2, nameof(Expense)); + + private FundTransactionType(int id, string name) : base(id, name) { } + + public static OperationResult FromId(int id) + { + var result = id switch + { + 1 => Deposit, + 2 => Expense, + _ => null + }; + + return result is null + ? OperationResult.Bad(DomainError.Validation("fund_transaction_type.unknown_id")) + : OperationResult.Good(result); + } + + public static implicit operator int(FundTransactionType t) => t.Id; +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/PresentationType.cs b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/PresentationType.cs new file mode 100644 index 0000000..b3bb7c2 --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/PresentationType.cs @@ -0,0 +1,32 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +public sealed class PresentationType : Enumeration +{ + /// Bulk container sold by weight (sacks, jars, bars). + public static readonly PresentationType BulkContainer = new(1, nameof(BulkContainer)); + + /// Pre-packaged unit sold as a closed unit (bags, bottles). + public static readonly PresentationType PackagedUnit = new(2, nameof(PackagedUnit)); + + private PresentationType(int id, string name) : base(id, name) { } + + public static OperationResult FromId(int id) + { + var result = id switch + { + 1 => BulkContainer, + 2 => PackagedUnit, + _ => null + }; + + return result is null + ? OperationResult.Bad(DomainError.Validation("presentation_type.unknown_id")) + : OperationResult.Good(result); + } + + public static implicit operator int(PresentationType t) => t.Id; +} diff --git a/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/SellMode.cs b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/SellMode.cs new file mode 100644 index 0000000..172f2bf --- /dev/null +++ b/backend/src/core/TuColmadoRD.Core.Domain/Enums/Inventory&Purchasing/SellMode.cs @@ -0,0 +1,36 @@ +using TuColmadoRD.Core.Domain.Base; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.ValueObjects.Base; + +namespace TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +public sealed class SellMode : Enumeration +{ + /// Sold as a closed unit (1 bag, 1 bottle). + public static readonly SellMode ByUnit = new(1, nameof(ByUnit)); + + /// Sold by weight/volume drawn from an open bulk container. + public static readonly SellMode ByWeight = new(2, nameof(ByWeight)); + + /// Sold as a whole container (e.g. a 10-lb portion-sack). + public static readonly SellMode ByContainer = new(3, nameof(ByContainer)); + + private SellMode(int id, string name) : base(id, name) { } + + public static OperationResult FromId(int id) + { + var result = id switch + { + 1 => ByUnit, + 2 => ByWeight, + 3 => ByContainer, + _ => null + }; + + return result is null + ? OperationResult.Bad(DomainError.Validation("sell_mode.unknown_id")) + : OperationResult.Good(result); + } + + public static implicit operator int(SellMode s) => s.Id; +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/BackgroundServices/CatalogSyncWorker.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/BackgroundServices/CatalogSyncWorker.cs index a6d170e..c01a6b3 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/BackgroundServices/CatalogSyncWorker.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/BackgroundServices/CatalogSyncWorker.cs @@ -151,41 +151,24 @@ private static async Task> UpsertProductAsync ProductSyncDto dto, CancellationToken ct) { - var costResult = Money.FromDecimal(0m); - var saleResult = Money.FromDecimal(dto.Price); var itbisResult = TaxRate.Create(0m); - - if (!costResult.IsGood || !saleResult.IsGood || !itbisResult.IsGood) + if (!itbisResult.IsGood) { return OperationResult.Bad( - new SyncError("ProductMappingFailed", "invalid_product_price_or_tax")); + new SyncError("ProductMappingFailed", "invalid_product_tax_rate")); } - var cost = costResult.Result!; - var sale = saleResult.Result!; var itbis = itbisResult.Result!; var existing = await dbContext.Products.FirstOrDefaultAsync(p => p.Id == dto.ProductId, ct); if (existing is null) { - var createResult = Product.RehydrateForCatalogSync(dto.ProductId, tenantId, dto.CategoryId, dto.Name, cost, sale, itbis); - if (!createResult.IsGood || !createResult.TryGetResult(out var created) || created is null) - { - return OperationResult.Bad( - new SyncError("ProductCreateFailed", "failed_to_create_local_product")); - } + var created = Product.Rehydrate(dto.ProductId, tenantId.Value, dto.Name, dto.CategoryId, itbis); dbContext.Products.Add(created); - return OperationResult.Good(new Unit()); } - var updateResult = existing.UpdateFromCatalogSync(dto.CategoryId, dto.Name, cost, sale); - if (!updateResult.IsGood) - { - return OperationResult.Bad( - new SyncError("ProductUpdateFailed", "failed_to_update_local_product")); - } - + existing.UpdateName(dto.Name); return OperationResult.Good(new Unit()); } diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/TuColmadoRD.Infrastructure.CrossCutting.csproj b/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/TuColmadoRD.Infrastructure.CrossCutting.csproj index 06a482d..9119c8b 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/TuColmadoRD.Infrastructure.CrossCutting.csproj +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.CrossCutting/TuColmadoRD.Infrastructure.CrossCutting.csproj @@ -9,11 +9,11 @@ - - - - - + + + + + diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Contexts/TuColmadoDbContext.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Contexts/TuColmadoDbContext.cs index a55a804..8df0e02 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Contexts/TuColmadoDbContext.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Contexts/TuColmadoDbContext.cs @@ -47,6 +47,13 @@ public TuColmadoDbContext(DbContextOptions options, ITenantP public DbSet Categories => Set(); public DbSet Products => Set(); + public DbSet ProductPresentations => Set(); + public DbSet StockContainers => Set(); + public DbSet PackagedStocks => Set(); + public DbSet StockEntries => Set(); + public DbSet StockEntryLines => Set(); + public DbSet MonetaryFunds => Set(); + public DbSet FundTransactions => Set(); public DbSet UnitConversions => Set(); public DbSet UnitOfMeasures => Set(); diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/MonetaryFundConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/MonetaryFundConfiguration.cs new file mode 100644 index 0000000..9d9b25d --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/MonetaryFundConfiguration.cs @@ -0,0 +1,78 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; + +namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; + +public class MonetaryFundConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("MonetaryFunds"); + builder.HasKey(f => f.Id); + + builder.OwnsOne(f => f.TenantId, b => + { + b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(f => f.Name).IsRequired().HasMaxLength(80); + builder.Property(f => f.CreatedAt).IsRequired(); + builder.Property(f => f.UpdatedAt).IsRequired(); + + builder.Property(f => f.CurrentBalance) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.HasMany(f => f.Transactions) + .WithOne() + .HasForeignKey(t => t.FundId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Ignore(f => f.DomainEvents); + } +} + +public class FundTransactionConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("FundTransactions"); + builder.HasKey(t => t.Id); + + builder.OwnsOne(t => t.TenantId, b => + { + b.Property(ten => ten.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(t => t.FundId).IsRequired(); + builder.Property(t => t.Description).IsRequired().HasMaxLength(200); + builder.Property(t => t.JustificationNote).HasMaxLength(500); + builder.Property(t => t.ReferenceId); + builder.Property(t => t.OccurredAt).IsRequired(); + + builder.Property(t => t.Type) + .HasConversion(v => v.Id, v => FundTransactionType.FromId(v).Result!) + .IsRequired(); + + builder.Property(t => t.Category) + .HasConversion( + v => v != null ? (int?)v.Id : null, + v => v.HasValue ? FundExpenseCategory.FromId(v.Value).Result : null); + + builder.Property(t => t.Amount) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.Property(t => t.BalanceAfter) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.HasIndex(t => t.FundId).HasDatabaseName("IX_FundTransactions_FundId"); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/PackagedStockConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/PackagedStockConfiguration.cs new file mode 100644 index 0000000..1ce6255 --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/PackagedStockConfiguration.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TuColmadoRD.Core.Domain.Entities.Inventory; + +namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; + +public class PackagedStockConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("PackagedStock"); + builder.HasKey(p => p.Id); + + builder.OwnsOne(p => p.TenantId, b => + { + b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(p => p.PresentationId).IsRequired(); + builder.Property(p => p.Quantity).IsRequired(); + builder.Property(p => p.LastUpdatedAt).IsRequired(); + + builder.HasIndex(p => p.PresentationId).IsUnique().HasDatabaseName("IX_PackagedStock_PresentationId"); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductConfiguration.cs index 6a0d065..a7bc9f9 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductConfiguration.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductConfiguration.cs @@ -1,7 +1,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using TuColmadoRD.Core.Domain.Entities.Inventory; -using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; using TuColmadoRD.Core.Domain.ValueObjects; namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; @@ -19,32 +18,18 @@ public void Configure(EntityTypeBuilder builder) builder.Property(p => p.IsActive).IsRequired(); builder.Property(p => p.CreatedAt).IsRequired(); builder.Property(p => p.UpdatedAt).IsRequired(); - builder.Property(p => p.StockQuantity).HasColumnType("decimal(18,4)").IsRequired(); - builder.OwnsOne(p => p.TenantId, b => + builder.OwnsOne(p => p.TenantId, b => { b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); }); - builder.Property(p => p.CostPrice) - .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result) - .HasColumnType("decimal(18,2)") - .IsRequired(); - - builder.Property(p => p.SalePrice) - .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result) - .HasColumnType("decimal(18,2)") - .IsRequired(); - builder.Property(p => p.ItbisRate) .HasConversion(v => v.Rate, v => TaxRate.Create(v).Result) .HasColumnType("decimal(5,4)") .IsRequired(); - builder.Property(p => p.UnitType) - .HasConversion(v => v.Id, v => UnitType.FromId(v).Result) - .IsRequired(); - builder.Ignore(p => p.DomainEvents); + builder.Ignore(p => p.Presentations); } } diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductPresentationConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductPresentationConfiguration.cs new file mode 100644 index 0000000..1ab5a7e --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/ProductPresentationConfiguration.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; +using TuColmadoRD.Core.Domain.ValueObjects; + +namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; + +public class ProductPresentationConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("ProductPresentations"); + builder.HasKey(p => p.Id); + + builder.OwnsOne(p => p.TenantId, b => + { + b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(p => p.ProductId).IsRequired(); + builder.Property(p => p.DisplayName).IsRequired().HasMaxLength(100); + builder.Property(p => p.Brand).HasMaxLength(80); + builder.Property(p => p.NominalCapacity).HasColumnType("decimal(18,4)"); + builder.Property(p => p.IsActive).IsRequired(); + builder.Property(p => p.CreatedAt).IsRequired(); + builder.Property(p => p.UpdatedAt).IsRequired(); + + builder.Property(p => p.PresentationType) + .HasConversion(v => v.Id, v => PresentationType.FromId(v).Result!) + .IsRequired(); + + builder.Property(p => p.SellMode) + .HasConversion(v => v.Id, v => SellMode.FromId(v).Result!) + .IsRequired(); + + builder.Property(p => p.MeasureUnit) + .HasConversion(v => (int)v, v => (UnitOfMeasure)v) + .IsRequired(); + + builder.Property(p => p.SalePrice) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.Property(p => p.CostPrice) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.Ignore(p => p.DomainEvents); + + builder.HasIndex(p => new { p.ProductId }).HasDatabaseName("IX_ProductPresentations_ProductId"); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockContainerConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockContainerConfiguration.cs new file mode 100644 index 0000000..25d3e9a --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockContainerConfiguration.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.Enums.Inventory_Purchasing; + +namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; + +public class StockContainerConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("StockContainers"); + builder.HasKey(c => c.Id); + + builder.OwnsOne(c => c.TenantId, b => + { + b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(c => c.PresentationId).IsRequired(); + builder.Property(c => c.ContainerCode).IsRequired().HasMaxLength(20); + builder.Property(c => c.NominalCapacity).HasColumnType("decimal(18,4)").IsRequired(); + builder.Property(c => c.ActualCapacity).HasColumnType("decimal(18,4)"); + builder.Property(c => c.CurrentRemaining).HasColumnType("decimal(18,4)").IsRequired(); + builder.Property(c => c.IsActiveSource).IsRequired(); + builder.Property(c => c.Notes).HasMaxLength(500); + builder.Property(c => c.PurchasedAt).IsRequired(); + builder.Property(c => c.OpenedAt); + builder.Property(c => c.EmptiedAt); + builder.Property(c => c.CreatedAt).IsRequired(); + builder.Property(c => c.UpdatedAt).IsRequired(); + + builder.Property(c => c.Status) + .HasConversion(v => v.Id, v => ContainerStatus.FromId(v).Result!) + .IsRequired(); + + builder.Ignore(c => c.DomainEvents); + + builder.HasIndex(c => c.PresentationId).HasDatabaseName("IX_StockContainers_PresentationId"); + builder.HasIndex(c => new { c.PresentationId, c.IsActiveSource }).HasDatabaseName("IX_StockContainers_PresentationId_IsActive"); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockEntryConfiguration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockEntryConfiguration.cs new file mode 100644 index 0000000..efd8cc5 --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/EntitiesConfigurations/Inventory/StockEntryConfiguration.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects; + +namespace TuColmadoRD.Infrastructure.Persistence.EntitiesConfigurations.Inventory; + +public class StockEntryConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("StockEntries"); + builder.HasKey(e => e.Id); + + builder.OwnsOne(e => e.TenantId, b => + { + b.Property(t => t.Value).HasColumnName("TenantId").IsRequired(); + }); + + builder.Property(e => e.PurchasedAt).IsRequired(); + builder.Property(e => e.SupplierName).HasMaxLength(120); + builder.Property(e => e.Notes).HasMaxLength(500); + builder.Property(e => e.FundTransactionId); + builder.Property(e => e.CreatedAt).IsRequired(); + + builder.Property(e => e.TotalCost) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.HasMany(e => e.Lines) + .WithOne() + .HasForeignKey(l => l.StockEntryId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Ignore(e => e.DomainEvents); + } +} + +public class StockEntryLineConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("StockEntryLines"); + builder.HasKey(l => l.Id); + + builder.Property(l => l.StockEntryId).IsRequired(); + builder.Property(l => l.PresentationId).IsRequired(); + builder.Property(l => l.ContainerCount).IsRequired(); + builder.Property(l => l.UnitsPerContainer).IsRequired(); + builder.Property(l => l.NominalSizePerUnit).HasColumnType("decimal(18,4)").IsRequired(); + + builder.Property(l => l.CostPerUnit) + .HasConversion(v => v.Amount, v => Money.FromDecimal(v).Result!) + .HasColumnType("decimal(18,2)") + .IsRequired(); + + builder.Ignore(l => l.TotalUnits); + builder.Ignore(l => l.TotalNominalWeight); + + builder.HasIndex(l => l.StockEntryId).HasDatabaseName("IX_StockEntryLines_StockEntryId"); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.Designer.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.Designer.cs new file mode 100644 index 0000000..9727782 --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.Designer.cs @@ -0,0 +1,2546 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +#nullable disable + +namespace TuColmadoRD.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(TuColmadoDbContext))] + [Migration("20260518234121_AddMultiPresentationStock")] + partial class AddMultiPresentationStock + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.16") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Audit.AuditTrail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NewValues") + .IsRequired() + .HasColumnType("text"); + + b.Property("OldValues") + .IsRequired() + .HasColumnType("text"); + + b.Property("TableName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("AuditTrails", "Audit"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Customers", "Customers"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.CustomerAccount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("LastActivity") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("CustomerAccounts", "Customers"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.DebtTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Concept") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomerAccountId") + .HasColumnType("uuid"); + + b.Property("CustomerAccountId1") + .HasColumnType("uuid"); + + b.Property("ReceiptReference") + .HasColumnType("text"); + + b.Property("TerminalId") + .HasColumnType("uuid"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CustomerAccountId"); + + b.HasIndex("CustomerAccountId1"); + + b.ToTable("DebtTransactions", "Customers"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.FiscalReceipt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IssuedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("NCF") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.Property("TrackId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("FiscalReceipts", "Fiscal"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.FiscalSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrentSequence") + .HasColumnType("integer"); + + b.Property("EndSequence") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(5) + .HasColumnType("character varying(5)"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("FiscalSequences", "Fiscal"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.NcfAnnulmentLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnnulledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("NCF") + .IsRequired() + .HasMaxLength(13) + .HasColumnType("character varying(13)"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("NcfAnnulmentLogs", "Fiscal"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.Tax", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Rate") + .HasColumnType("decimal(5,4)") + .HasColumnName("RatePercentage"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Taxes", "Fiscal"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.HumanResources.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("HireDate") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Role") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Employees", "HumanResources"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.HumanResources.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("WorkShifts", "HumanResources"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.HasKey("Id"); + + b.ToTable("Categories", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.FundTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("BalanceAfter") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("FundId") + .HasColumnType("uuid"); + + b.Property("JustificationNote") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReferenceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("FundId") + .HasDatabaseName("IX_FundTransactions_FundId"); + + b.ToTable("FundTransactions", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MonetaryFunds", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.PackagedStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("LastUpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PresentationId") + .IsUnique() + .HasDatabaseName("IX_PackagedStock_PresentationId"); + + b.ToTable("PackagedStock", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("ItbisRate") + .HasColumnType("decimal(5,4)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Products", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.ProductPresentation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Brand") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CostPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("MeasureUnit") + .HasColumnType("integer"); + + b.Property("NominalCapacity") + .HasColumnType("decimal(18,4)"); + + b.Property("PresentationType") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("SalePrice") + .HasColumnType("decimal(18,2)"); + + b.Property("SellMode") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ProductId") + .HasDatabaseName("IX_ProductPresentations_ProductId"); + + b.ToTable("ProductPresentations", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActualCapacity") + .HasColumnType("decimal(18,4)"); + + b.Property("ContainerCode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentRemaining") + .HasColumnType("decimal(18,4)"); + + b.Property("EmptiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActiveSource") + .HasColumnType("boolean"); + + b.Property("NominalCapacity") + .HasColumnType("decimal(18,4)"); + + b.Property("Notes") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OpenedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("PurchasedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("PresentationId") + .HasDatabaseName("IX_StockContainers_PresentationId"); + + b.HasIndex("PresentationId", "IsActiveSource") + .HasDatabaseName("IX_StockContainers_PresentationId_IsActive"); + + b.ToTable("StockContainers", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FundTransactionId") + .HasColumnType("uuid"); + + b.Property("Notes") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PurchasedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SupplierName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("TotalCost") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.ToTable("StockEntries", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntryLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ContainerCount") + .HasColumnType("integer"); + + b.Property("CostPerUnit") + .HasColumnType("decimal(18,2)"); + + b.Property("NominalSizePerUnit") + .HasColumnType("decimal(18,4)"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("StockEntryId") + .HasColumnType("uuid"); + + b.Property("UnitsPerContainer") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("StockEntryId") + .HasDatabaseName("IX_StockEntryLines_StockEntryId"); + + b.ToTable("StockEntryLines", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.UnitConversion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Factor") + .HasColumnType("decimal(18,6)"); + + b.Property("FromUnitId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("ToUnitId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("FromUnitId"); + + b.HasIndex("ProductId"); + + b.HasIndex("ToUnitId"); + + b.ToTable("UnitConversions", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.UnitOfMeasureEntity", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Abbreviation") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("IsFractionable") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("UnitOfMeasures", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Logistics.DeliveryOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConfirmationCode") + .IsRequired() + .HasMaxLength(6) + .HasColumnType("character varying(6)"); + + b.Property("DeliveredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryPersonId") + .HasColumnType("uuid"); + + b.Property("DispatchedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeliveryPersonId"); + + b.ToTable("DeliveryOrders", "Logistics"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Logistics.DeliveryPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsAvailable") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("VehiclePlate") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("Id"); + + b.ToTable("DeliveryPersons", "Logistics"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("PurchaseOrderId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("decimal(18,4)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitCost") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("PurchaseOrderId"); + + b.ToTable("PurchaseDetails", "Purchasing"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("OrderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ShiftId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("SupplierNcf") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TotalAmount") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("PurchaseOrders", "Purchasing"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Purchasing"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.Sale", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CashierName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("ChangeDueAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("NcfNumber") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Notes") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("ReceiptNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ShiftId") + .HasColumnType("uuid"); + + b.Property("StatusId") + .HasColumnType("integer"); + + b.Property("SubtotalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TerminalId") + .HasColumnType("uuid"); + + b.Property("TotalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalItbisAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaidAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("VoidReason") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("VoidedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Sales", "Sales"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SaleDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("decimal(18,4)") + .HasColumnName("Quantity"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)") + .HasColumnName("SubTotal"); + + b.Property("TaxAmount") + .HasColumnType("decimal(18,2)") + .HasColumnName("TaxAmount"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)") + .HasColumnName("UnitPrice"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.ToTable("SaleDetails", "Sales"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SaleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CostPriceAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("ItbisRateValue") + .HasColumnType("decimal(9,6)"); + + b.Property("LineItbisAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("LineSubtotalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("LineTotalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("ProductName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("QuantityValue") + .HasColumnType("decimal(18,4)"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.Property("UnitPriceAmount") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("SaleId"); + + b.ToTable("SaleItems", "Sales"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SalePayment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AmountValue") + .HasColumnType("decimal(18,2)"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodId") + .HasColumnType("integer"); + + b.Property("ReceivedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Reference") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SaleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("SaleId"); + + b.ToTable("SalePayments", "Sales"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.Shift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActualCashAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("CashDifferenceAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("CashierName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ClosedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ClosingCashAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("ExpectedCashAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OpenedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OpeningCashAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TerminalId") + .HasColumnType("uuid"); + + b.Property("TotalAccountPayments") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalCardIn") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalCashIn") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalCashSales") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalExpenses") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalSalesAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalSalesCount") + .HasColumnType("integer"); + + b.Property("TotalTransferIn") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TerminalId", "Status"); + + b.ToTable("Shifts", "Sales"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.System.OutboxMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastError") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RetryCount") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0); + + b.Property("Type") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Type"); + + b.HasIndex("ProcessedAt", "CreatedAt"); + + b.ToTable("OutboxMessages", "System"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.System.SystemConfig", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Key"); + + b.ToTable("SystemConfigs", "System"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.System.TenantProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAddress") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("BusinessName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Phone") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("TenantProfiles", "System"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.CashBox", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("CashBoxes", "Treasury"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.CashDrawer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsOpen") + .HasColumnType("boolean"); + + b.Property("ShiftId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ShiftId"); + + b.ToTable("CashDrawers", "Treasury"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.Expense", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CashBoxId") + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasColumnType("text"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ReferenceNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("CashBoxId"); + + b.ToTable("Expenses", "Treasury"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.PettyCash", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("PettyCashes", "Treasury"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Audit.AuditTrail", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("AuditTrailId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("AuditTrailId"); + + b1.ToTable("AuditTrails", "Audit"); + + b1.WithOwner() + .HasForeignKey("AuditTrailId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.Customer", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Phone", "ContactPhone", b1 => + { + b1.Property("CustomerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("ContactPhone"); + + b1.HasKey("CustomerId"); + + b1.ToTable("Customers", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Cedula", "DocumentId", b1 => + { + b1.Property("CustomerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("DocumentId"); + + b1.HasKey("CustomerId"); + + b1.ToTable("Customers", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Address", "HomeAddress", b1 => + { + b1.Property("CustomerId") + .HasColumnType("uuid"); + + b1.Property("HouseNumber") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("Address_HouseNumber"); + + b1.Property("Latitude") + .HasColumnType("double precision") + .HasColumnName("Address_Latitude"); + + b1.Property("Longitude") + .HasColumnType("double precision") + .HasColumnName("Address_Longitude"); + + b1.Property("Province") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Address_Province"); + + b1.Property("Reference") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("Address_Reference"); + + b1.Property("Sector") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Address_Sector"); + + b1.Property("Street") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Address_Street"); + + b1.HasKey("CustomerId"); + + b1.ToTable("Customers", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("CustomerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("CustomerId"); + + b1.ToTable("Customers", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerId"); + }); + + b.Navigation("ContactPhone"); + + b.Navigation("DocumentId"); + + b.Navigation("HomeAddress"); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.CustomerAccount", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "Balance", b1 => + { + b1.Property("CustomerAccountId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("Balance"); + + b1.HasKey("CustomerAccountId"); + + b1.ToTable("CustomerAccounts", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerAccountId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "CreditLimit", b1 => + { + b1.Property("CustomerAccountId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("CreditLimit"); + + b1.HasKey("CustomerAccountId"); + + b1.ToTable("CustomerAccounts", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerAccountId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("CustomerAccountId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("CustomerAccountId"); + + b1.ToTable("CustomerAccounts", "Customers"); + + b1.WithOwner() + .HasForeignKey("CustomerAccountId"); + }); + + b.Navigation("Balance") + .IsRequired(); + + b.Navigation("CreditLimit") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.DebtTransaction", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Customers.CustomerAccount", null) + .WithMany() + .HasForeignKey("CustomerAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TuColmadoRD.Core.Domain.Entities.Customers.CustomerAccount", null) + .WithMany("Transactions") + .HasForeignKey("CustomerAccountId1"); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "Amount", b1 => + { + b1.Property("DebtTransactionId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("Amount"); + + b1.HasKey("DebtTransactionId"); + + b1.ToTable("DebtTransactions", "Customers"); + + b1.WithOwner() + .HasForeignKey("DebtTransactionId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("DebtTransactionId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("DebtTransactionId"); + + b1.ToTable("DebtTransactions", "Customers"); + + b1.WithOwner() + .HasForeignKey("DebtTransactionId"); + }); + + b.Navigation("Amount") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.FiscalReceipt", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Rnc", "BuyerRnc", b1 => + { + b1.Property("FiscalReceiptId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("BuyerRnc"); + + b1.HasKey("FiscalReceiptId"); + + b1.ToTable("FiscalReceipts", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("FiscalReceiptId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("FiscalReceiptId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("FiscalReceiptId"); + + b1.ToTable("FiscalReceipts", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("FiscalReceiptId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "TotalTaxed", b1 => + { + b1.Property("FiscalReceiptId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("TotalTaxed"); + + b1.HasKey("FiscalReceiptId"); + + b1.ToTable("FiscalReceipts", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("FiscalReceiptId"); + }); + + b.Navigation("BuyerRnc"); + + b.Navigation("TenantId") + .IsRequired(); + + b.Navigation("TotalTaxed") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.FiscalSequence", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("FiscalSequenceId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("FiscalSequenceId"); + + b1.ToTable("FiscalSequences", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("FiscalSequenceId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.NcfAnnulmentLog", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("NcfAnnulmentLogId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("NcfAnnulmentLogId"); + + b1.ToTable("NcfAnnulmentLogs", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("NcfAnnulmentLogId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Fiscal.Tax", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("TaxId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("TaxId"); + + b1.ToTable("Taxes", "Fiscal"); + + b1.WithOwner() + .HasForeignKey("TaxId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.HumanResources.Employee", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Cedula", "IdCard", b1 => + { + b1.Property("EmployeeId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("IdCard"); + + b1.HasKey("EmployeeId"); + + b1.ToTable("Employees", "HumanResources"); + + b1.WithOwner() + .HasForeignKey("EmployeeId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Phone", "Phone", b1 => + { + b1.Property("EmployeeId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("Phone"); + + b1.HasKey("EmployeeId"); + + b1.ToTable("Employees", "HumanResources"); + + b1.WithOwner() + .HasForeignKey("EmployeeId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("EmployeeId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("EmployeeId"); + + b1.ToTable("Employees", "HumanResources"); + + b1.WithOwner() + .HasForeignKey("EmployeeId"); + }); + + b.Navigation("IdCard"); + + b.Navigation("Phone"); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.HumanResources.WorkShift", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("WorkShiftId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("WorkShiftId"); + + b1.ToTable("WorkShifts", "HumanResources"); + + b1.WithOwner() + .HasForeignKey("WorkShiftId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Category", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("CategoryId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("CategoryId"); + + b1.ToTable("Categories", "Inventory"); + + b1.WithOwner() + .HasForeignKey("CategoryId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.FundTransaction", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", null) + .WithMany("Transactions") + .HasForeignKey("FundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("FundTransactionId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("FundTransactionId"); + + b1.ToTable("FundTransactions", "Inventory"); + + b1.WithOwner() + .HasForeignKey("FundTransactionId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("MonetaryFundId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("MonetaryFundId"); + + b1.ToTable("MonetaryFunds", "Inventory"); + + b1.WithOwner() + .HasForeignKey("MonetaryFundId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.PackagedStock", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("PackagedStockId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("PackagedStockId"); + + b1.ToTable("PackagedStock", "Inventory"); + + b1.WithOwner() + .HasForeignKey("PackagedStockId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Product", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("ProductId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("ProductId"); + + b1.ToTable("Products", "Inventory"); + + b1.WithOwner() + .HasForeignKey("ProductId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.ProductPresentation", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("ProductPresentationId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("ProductPresentationId"); + + b1.ToTable("ProductPresentations", "Inventory"); + + b1.WithOwner() + .HasForeignKey("ProductPresentationId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockContainer", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("StockContainerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("StockContainerId"); + + b1.ToTable("StockContainers", "Inventory"); + + b1.WithOwner() + .HasForeignKey("StockContainerId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("StockEntryId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("StockEntryId"); + + b1.ToTable("StockEntries", "Inventory"); + + b1.WithOwner() + .HasForeignKey("StockEntryId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntryLine", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", null) + .WithMany("Lines") + .HasForeignKey("StockEntryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.UnitConversion", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.UnitOfMeasureEntity", "FromUnit") + .WithMany() + .HasForeignKey("FromUnitId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.Product", null) + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.UnitOfMeasureEntity", "ToUnit") + .WithMany() + .HasForeignKey("ToUnitId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("UnitConversionId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("UnitConversionId"); + + b1.ToTable("UnitConversions", "Inventory"); + + b1.WithOwner() + .HasForeignKey("UnitConversionId"); + }); + + b.Navigation("FromUnit"); + + b.Navigation("TenantId") + .IsRequired(); + + b.Navigation("ToUnit"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Logistics.DeliveryOrder", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Logistics.DeliveryPerson", null) + .WithMany() + .HasForeignKey("DeliveryPersonId") + .OnDelete(DeleteBehavior.Restrict); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Address", "Destination", b1 => + { + b1.Property("DeliveryOrderId") + .HasColumnType("uuid"); + + b1.Property("HouseNumber") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("Destination_HouseNumber"); + + b1.Property("Latitude") + .HasColumnType("double precision") + .HasColumnName("Destination_Latitude"); + + b1.Property("Longitude") + .HasColumnType("double precision") + .HasColumnName("Destination_Longitude"); + + b1.Property("Province") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Destination_Province"); + + b1.Property("Reference") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("Destination_Reference"); + + b1.Property("Sector") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Destination_Sector"); + + b1.Property("Street") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Destination_Street"); + + b1.HasKey("DeliveryOrderId"); + + b1.ToTable("DeliveryOrders", "Logistics"); + + b1.WithOwner() + .HasForeignKey("DeliveryOrderId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("DeliveryOrderId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("DeliveryOrderId"); + + b1.ToTable("DeliveryOrders", "Logistics"); + + b1.WithOwner() + .HasForeignKey("DeliveryOrderId"); + }); + + b.Navigation("Destination") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Logistics.DeliveryPerson", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Phone", "ContactPhone", b1 => + { + b1.Property("DeliveryPersonId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("ContactPhone"); + + b1.HasKey("DeliveryPersonId"); + + b1.ToTable("DeliveryPersons", "Logistics"); + + b1.WithOwner() + .HasForeignKey("DeliveryPersonId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("DeliveryPersonId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("DeliveryPersonId"); + + b1.ToTable("DeliveryPersons", "Logistics"); + + b1.WithOwner() + .HasForeignKey("DeliveryPersonId"); + }); + + b.Navigation("ContactPhone"); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseDetail", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.Product", null) + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseOrder", null) + .WithMany("Details") + .HasForeignKey("PurchaseOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseOrder", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Purchasing.Supplier", null) + .WithMany() + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("PurchaseOrderId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("PurchaseOrderId"); + + b1.ToTable("PurchaseOrders", "Purchasing"); + + b1.WithOwner() + .HasForeignKey("PurchaseOrderId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.Supplier", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Rnc", "Rnc", b1 => + { + b1.Property("SupplierId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("Rnc"); + + b1.HasKey("SupplierId"); + + b1.ToTable("Suppliers", "Purchasing"); + + b1.WithOwner() + .HasForeignKey("SupplierId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("SupplierId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("SupplierId"); + + b1.ToTable("Suppliers", "Purchasing"); + + b1.WithOwner() + .HasForeignKey("SupplierId"); + }); + + b.Navigation("Rnc") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.Sale", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("SaleId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("SaleId"); + + b1.ToTable("Sales", "Sales"); + + b1.WithOwner() + .HasForeignKey("SaleId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SaleDetail", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.Product", null) + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SaleItem", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Sales.Sale", null) + .WithMany("Items") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.SalePayment", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Sales.Sale", null) + .WithMany("Payments") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.Shift", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("ShiftId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("ShiftId"); + + b1.ToTable("Shifts", "Sales"); + + b1.WithOwner() + .HasForeignKey("ShiftId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.System.TenantProfile", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Rnc", "Rnc", b1 => + { + b1.Property("TenantProfileId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("Rnc"); + + b1.HasKey("TenantProfileId"); + + b1.ToTable("TenantProfiles", "System"); + + b1.WithOwner() + .HasForeignKey("TenantProfileId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("TenantProfileId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("TenantProfileId"); + + b1.ToTable("TenantProfiles", "System"); + + b1.WithOwner() + .HasForeignKey("TenantProfileId"); + }); + + b.Navigation("Rnc"); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.CashBox", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "Balance", b1 => + { + b1.Property("CashBoxId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("Balance"); + + b1.HasKey("CashBoxId"); + + b1.ToTable("CashBoxes", "Treasury"); + + b1.WithOwner() + .HasForeignKey("CashBoxId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("CashBoxId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("CashBoxId"); + + b1.ToTable("CashBoxes", "Treasury"); + + b1.WithOwner() + .HasForeignKey("CashBoxId"); + }); + + b.Navigation("Balance") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.CashDrawer", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Sales.Shift", null) + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "CurrentBalance", b1 => + { + b1.Property("CashDrawerId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("CurrentBalance"); + + b1.HasKey("CashDrawerId"); + + b1.ToTable("CashDrawers", "Treasury"); + + b1.WithOwner() + .HasForeignKey("CashDrawerId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "OpeningBalance", b1 => + { + b1.Property("CashDrawerId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("OpeningBalance"); + + b1.HasKey("CashDrawerId"); + + b1.ToTable("CashDrawers", "Treasury"); + + b1.WithOwner() + .HasForeignKey("CashDrawerId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("CashDrawerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("CashDrawerId"); + + b1.ToTable("CashDrawers", "Treasury"); + + b1.WithOwner() + .HasForeignKey("CashDrawerId"); + }); + + b.Navigation("CurrentBalance") + .IsRequired(); + + b.Navigation("OpeningBalance") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.Expense", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Treasury.CashBox", null) + .WithMany() + .HasForeignKey("CashBoxId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "Amount", b1 => + { + b1.Property("ExpenseId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("Amount"); + + b1.HasKey("ExpenseId"); + + b1.ToTable("Expenses", "Treasury"); + + b1.WithOwner() + .HasForeignKey("ExpenseId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("ExpenseId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("ExpenseId"); + + b1.ToTable("Expenses", "Treasury"); + + b1.WithOwner() + .HasForeignKey("ExpenseId"); + }); + + b.Navigation("Amount") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Treasury.PettyCash", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "Balance", b1 => + { + b1.Property("PettyCashId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("Balance"); + + b1.HasKey("PettyCashId"); + + b1.ToTable("PettyCashes", "Treasury"); + + b1.WithOwner() + .HasForeignKey("PettyCashId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.Money", "MaxLimit", b1 => + { + b1.Property("PettyCashId") + .HasColumnType("uuid"); + + b1.Property("Amount") + .HasColumnType("decimal(18,2)") + .HasColumnName("MaxLimit"); + + b1.HasKey("PettyCashId"); + + b1.ToTable("PettyCashes", "Treasury"); + + b1.WithOwner() + .HasForeignKey("PettyCashId"); + }); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("PettyCashId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("PettyCashId"); + + b1.ToTable("PettyCashes", "Treasury"); + + b1.WithOwner() + .HasForeignKey("PettyCashId"); + }); + + b.Navigation("Balance") + .IsRequired(); + + b.Navigation("MaxLimit") + .IsRequired(); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Customers.CustomerAccount", b => + { + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseOrder", b => + { + b.Navigation("Details"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Sales.Sale", b => + { + b.Navigation("Items"); + + b.Navigation("Payments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.cs new file mode 100644 index 0000000..11c6e02 --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/20260518234121_AddMultiPresentationStock.cs @@ -0,0 +1,293 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TuColmadoRD.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddMultiPresentationStock : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CostPrice", + schema: "Inventory", + table: "Products"); + + migrationBuilder.DropColumn( + name: "SalePrice", + schema: "Inventory", + table: "Products"); + + migrationBuilder.DropColumn( + name: "StockQuantity", + schema: "Inventory", + table: "Products"); + + migrationBuilder.DropColumn( + name: "UnitType", + schema: "Inventory", + table: "Products"); + + migrationBuilder.CreateTable( + name: "MonetaryFunds", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "character varying(80)", maxLength: 80, nullable: false), + CurrentBalance = table.Column(type: "numeric(18,2)", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MonetaryFunds", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PackagedStock", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + PresentationId = table.Column(type: "uuid", nullable: false), + Quantity = table.Column(type: "integer", nullable: false), + LastUpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PackagedStock", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProductPresentations", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + ProductId = table.Column(type: "uuid", nullable: false), + DisplayName = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + PresentationType = table.Column(type: "integer", nullable: false), + SellMode = table.Column(type: "integer", nullable: false), + MeasureUnit = table.Column(type: "integer", nullable: false), + SalePrice = table.Column(type: "numeric(18,2)", nullable: false), + CostPrice = table.Column(type: "numeric(18,2)", nullable: false), + Brand = table.Column(type: "character varying(80)", maxLength: 80, nullable: false), + NominalCapacity = table.Column(type: "numeric(18,4)", nullable: true), + IsActive = table.Column(type: "boolean", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductPresentations", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "StockContainers", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + PresentationId = table.Column(type: "uuid", nullable: false), + ContainerCode = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + NominalCapacity = table.Column(type: "numeric(18,4)", nullable: false), + ActualCapacity = table.Column(type: "numeric(18,4)", nullable: true), + CurrentRemaining = table.Column(type: "numeric(18,4)", nullable: false), + Status = table.Column(type: "integer", nullable: false), + IsActiveSource = table.Column(type: "boolean", nullable: false), + Notes = table.Column(type: "character varying(500)", maxLength: 500, nullable: false), + PurchasedAt = table.Column(type: "timestamp with time zone", nullable: false), + OpenedAt = table.Column(type: "timestamp with time zone", nullable: true), + EmptiedAt = table.Column(type: "timestamp with time zone", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_StockContainers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "StockEntries", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + PurchasedAt = table.Column(type: "timestamp with time zone", nullable: false), + SupplierName = table.Column(type: "character varying(120)", maxLength: 120, nullable: false), + Notes = table.Column(type: "character varying(500)", maxLength: 500, nullable: false), + TotalCost = table.Column(type: "numeric(18,2)", nullable: false), + FundTransactionId = table.Column(type: "uuid", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_StockEntries", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "FundTransactions", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + FundId = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "integer", nullable: false), + Amount = table.Column(type: "numeric(18,2)", nullable: false), + Category = table.Column(type: "integer", nullable: true), + Description = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + JustificationNote = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + ReferenceId = table.Column(type: "uuid", nullable: true), + BalanceAfter = table.Column(type: "numeric(18,2)", nullable: false), + OccurredAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FundTransactions", x => x.Id); + table.ForeignKey( + name: "FK_FundTransactions_MonetaryFunds_FundId", + column: x => x.FundId, + principalSchema: "Inventory", + principalTable: "MonetaryFunds", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "StockEntryLines", + schema: "Inventory", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + StockEntryId = table.Column(type: "uuid", nullable: false), + PresentationId = table.Column(type: "uuid", nullable: false), + ContainerCount = table.Column(type: "integer", nullable: false), + UnitsPerContainer = table.Column(type: "integer", nullable: false), + NominalSizePerUnit = table.Column(type: "numeric(18,4)", nullable: false), + CostPerUnit = table.Column(type: "numeric(18,2)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_StockEntryLines", x => x.Id); + table.ForeignKey( + name: "FK_StockEntryLines_StockEntries_StockEntryId", + column: x => x.StockEntryId, + principalSchema: "Inventory", + principalTable: "StockEntries", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_FundTransactions_FundId", + schema: "Inventory", + table: "FundTransactions", + column: "FundId"); + + migrationBuilder.CreateIndex( + name: "IX_PackagedStock_PresentationId", + schema: "Inventory", + table: "PackagedStock", + column: "PresentationId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ProductPresentations_ProductId", + schema: "Inventory", + table: "ProductPresentations", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_StockContainers_PresentationId", + schema: "Inventory", + table: "StockContainers", + column: "PresentationId"); + + migrationBuilder.CreateIndex( + name: "IX_StockContainers_PresentationId_IsActive", + schema: "Inventory", + table: "StockContainers", + columns: new[] { "PresentationId", "IsActiveSource" }); + + migrationBuilder.CreateIndex( + name: "IX_StockEntryLines_StockEntryId", + schema: "Inventory", + table: "StockEntryLines", + column: "StockEntryId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FundTransactions", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "PackagedStock", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "ProductPresentations", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "StockContainers", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "StockEntryLines", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "MonetaryFunds", + schema: "Inventory"); + + migrationBuilder.DropTable( + name: "StockEntries", + schema: "Inventory"); + + migrationBuilder.AddColumn( + name: "CostPrice", + schema: "Inventory", + table: "Products", + type: "numeric(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "SalePrice", + schema: "Inventory", + table: "Products", + type: "numeric(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "StockQuantity", + schema: "Inventory", + table: "Products", + type: "numeric(18,4)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "UnitType", + schema: "Inventory", + table: "Products", + type: "integer", + nullable: false, + defaultValue: 0); + } + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/TuColmadoDbContextModelSnapshot.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/TuColmadoDbContextModelSnapshot.cs index f2abb2f..c88e958 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/TuColmadoDbContextModelSnapshot.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Migrations/TuColmadoDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("ProductVersion", "9.0.16") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -305,18 +305,108 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Categories", "Inventory"); }); - modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Product", b => + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.FundTransaction", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("CategoryId") + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("BalanceAfter") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("FundId") .HasColumnType("uuid"); - b.Property("CostPrice") + b.Property("JustificationNote") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReferenceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("FundId") + .HasDatabaseName("IX_FundTransactions_FundId"); + + b.ToTable("FundTransactions", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentBalance") .HasColumnType("decimal(18,2)"); + b.Property("Name") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MonetaryFunds", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.PackagedStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("LastUpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PresentationId") + .IsUnique() + .HasDatabaseName("IX_PackagedStock_PresentationId"); + + b.ToTable("PackagedStock", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); @@ -331,13 +421,112 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(120) .HasColumnType("character varying(120)"); + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Products", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.ProductPresentation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Brand") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CostPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("MeasureUnit") + .HasColumnType("integer"); + + b.Property("NominalCapacity") + .HasColumnType("decimal(18,4)"); + + b.Property("PresentationType") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("uuid"); + b.Property("SalePrice") .HasColumnType("decimal(18,2)"); - b.Property("StockQuantity") + b.Property("SellMode") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ProductId") + .HasDatabaseName("IX_ProductPresentations_ProductId"); + + b.ToTable("ProductPresentations", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActualCapacity") .HasColumnType("decimal(18,4)"); - b.Property("UnitType") + b.Property("ContainerCode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentRemaining") + .HasColumnType("decimal(18,4)"); + + b.Property("EmptiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActiveSource") + .HasColumnType("boolean"); + + b.Property("NominalCapacity") + .HasColumnType("decimal(18,4)"); + + b.Property("Notes") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OpenedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("PurchasedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") .HasColumnType("integer"); b.Property("UpdatedAt") @@ -345,7 +534,78 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.ToTable("Products", "Inventory"); + b.HasIndex("PresentationId") + .HasDatabaseName("IX_StockContainers_PresentationId"); + + b.HasIndex("PresentationId", "IsActiveSource") + .HasDatabaseName("IX_StockContainers_PresentationId_IsActive"); + + b.ToTable("StockContainers", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FundTransactionId") + .HasColumnType("uuid"); + + b.Property("Notes") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PurchasedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SupplierName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("TotalCost") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.ToTable("StockEntries", "Inventory"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntryLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ContainerCount") + .HasColumnType("integer"); + + b.Property("CostPerUnit") + .HasColumnType("decimal(18,2)"); + + b.Property("NominalSizePerUnit") + .HasColumnType("decimal(18,4)"); + + b.Property("PresentationId") + .HasColumnType("uuid"); + + b.Property("StockEntryId") + .HasColumnType("uuid"); + + b.Property("UnitsPerContainer") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("StockEntryId") + .HasDatabaseName("IX_StockEntryLines_StockEntryId"); + + b.ToTable("StockEntryLines", "Inventory"); }); modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.UnitConversion", b => @@ -1475,6 +1735,81 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.FundTransaction", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", null) + .WithMany("Transactions") + .HasForeignKey("FundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("FundTransactionId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("FundTransactionId"); + + b1.ToTable("FundTransactions", "Inventory"); + + b1.WithOwner() + .HasForeignKey("FundTransactionId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("MonetaryFundId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("MonetaryFundId"); + + b1.ToTable("MonetaryFunds", "Inventory"); + + b1.WithOwner() + .HasForeignKey("MonetaryFundId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.PackagedStock", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("PackagedStockId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("PackagedStockId"); + + b1.ToTable("PackagedStock", "Inventory"); + + b1.WithOwner() + .HasForeignKey("PackagedStockId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.Product", b => { b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => @@ -1498,6 +1833,84 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.ProductPresentation", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("ProductPresentationId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("ProductPresentationId"); + + b1.ToTable("ProductPresentations", "Inventory"); + + b1.WithOwner() + .HasForeignKey("ProductPresentationId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockContainer", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("StockContainerId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("StockContainerId"); + + b1.ToTable("StockContainers", "Inventory"); + + b1.WithOwner() + .HasForeignKey("StockContainerId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.OwnsOne("TuColmadoRD.Core.Domain.ValueObjects.TenantIdentifier", "TenantId", b1 => + { + b1.Property("StockEntryId") + .HasColumnType("uuid"); + + b1.Property("Value") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b1.HasKey("StockEntryId"); + + b1.ToTable("StockEntries", "Inventory"); + + b1.WithOwner() + .HasForeignKey("StockEntryId"); + }); + + b.Navigation("TenantId") + .IsRequired(); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntryLine", b => + { + b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", null) + .WithMany("Lines") + .HasForeignKey("StockEntryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.UnitConversion", b => { b.HasOne("TuColmadoRD.Core.Domain.Entities.Inventory.UnitOfMeasureEntity", "FromUnit") @@ -2103,6 +2516,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Transactions"); }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.MonetaryFund", b => + { + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Inventory.StockEntry", b => + { + b.Navigation("Lines"); + }); + modelBuilder.Entity("TuColmadoRD.Core.Domain.Entities.Purchasing.PurchaseOrder", b => { b.Navigation("Details"); diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/MonetaryFundRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/MonetaryFundRepository.cs new file mode 100644 index 0000000..fc24bcb --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/MonetaryFundRepository.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Infrastructure.Persistence.Repositories.Inventory; + +public sealed class MonetaryFundRepository(TuColmadoDbContext dbContext) : IMonetaryFundRepository +{ + public async Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default) + { + var fund = await dbContext.MonetaryFunds + .Include(f => f.Transactions) + .FirstOrDefaultAsync(f => f.Id == id && f.TenantId.Value == tenantId, ct); + + return fund is null + ? OperationResult.Bad(DomainError.NotFound("fund.not_found")) + : OperationResult.Good(fund); + } + + public async Task GetDefaultAsync(Guid tenantId, CancellationToken ct = default) + { + return await dbContext.MonetaryFunds + .OrderBy(f => f.CreatedAt) + .FirstOrDefaultAsync(f => f.TenantId.Value == tenantId, ct); + } + + public async Task> GetAllAsync(Guid tenantId, CancellationToken ct = default) + { + return await dbContext.MonetaryFunds + .Where(f => f.TenantId.Value == tenantId) + .OrderBy(f => f.CreatedAt) + .AsNoTracking() + .ToListAsync(ct); + } + + public async Task AddAsync(MonetaryFund fund, CancellationToken ct = default) + { + await dbContext.MonetaryFunds.AddAsync(fund, ct); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PackagedStockRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PackagedStockRepository.cs new file mode 100644 index 0000000..5e461ea --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PackagedStockRepository.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Infrastructure.Persistence.Repositories.Inventory; + +public sealed class PackagedStockRepository(TuColmadoDbContext dbContext) : IPackagedStockRepository +{ + public async Task GetByPresentationIdAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default) + { + return await dbContext.PackagedStocks + .FirstOrDefaultAsync(s => s.PresentationId == presentationId && s.TenantId.Value == tenantId, ct); + } + + public async Task AddAsync(PackagedStock stock, CancellationToken ct = default) + { + await dbContext.PackagedStocks.AddAsync(stock, ct); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PresentationRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PresentationRepository.cs new file mode 100644 index 0000000..c8d1f8c --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/PresentationRepository.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Infrastructure.Persistence.Repositories.Inventory; + +public sealed class PresentationRepository(TuColmadoDbContext dbContext) : IPresentationRepository +{ + public async Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default) + { + var presentation = await dbContext.ProductPresentations + .FirstOrDefaultAsync(p => p.Id == id && p.TenantId.Value == tenantId, ct); + + return presentation is null + ? OperationResult.Bad(DomainError.NotFound("presentation.not_found")) + : OperationResult.Good(presentation); + } + + public async Task> GetByProductIdAsync(Guid productId, Guid tenantId, CancellationToken ct = default) + { + return await dbContext.ProductPresentations + .Where(p => p.ProductId == productId && p.TenantId.Value == tenantId) + .ToListAsync(ct); + } + + public async Task AddAsync(ProductPresentation presentation, CancellationToken ct = default) + { + await dbContext.ProductPresentations.AddAsync(presentation, ct); + } + + public async Task ProductExistsAsync(Guid productId, Guid tenantId, CancellationToken ct = default) + { + return await dbContext.Products + .AnyAsync(p => p.Id == productId && p.TenantId.Value == tenantId, ct); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/ProductReadRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/ProductReadRepository.cs index 3d1894e..b1e5bc4 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/ProductReadRepository.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/ProductReadRepository.cs @@ -32,12 +32,7 @@ public ProductReadRepository(TuColmadoDbContext dbContext) p.Name, p.CategoryId, c.Name, - p.CostPrice, - p.SalePrice, - p.ItbisRate, - p.UnitType, - p.UnitType.Name, - p.StockQuantity, + p.ItbisRate.Rate, p.IsActive, p.UpdatedAt)) .FirstOrDefaultAsync(ct); @@ -83,12 +78,7 @@ public async Task> GetPagedAsync(GetProductsPagedQuery q p.Name, p.CategoryId, c.Name, - p.CostPrice, - p.SalePrice, - p.ItbisRate, - p.UnitType, - p.UnitType.Name, - p.StockQuantity, + p.ItbisRate.Rate, p.IsActive, p.UpdatedAt)) .ToListAsync(ct); diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockContainerRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockContainerRepository.cs new file mode 100644 index 0000000..01bbe4f --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockContainerRepository.cs @@ -0,0 +1,48 @@ +using Microsoft.EntityFrameworkCore; +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Domain.Base.Result; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Core.Domain.ValueObjects.Base; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Infrastructure.Persistence.Repositories.Inventory; + +public sealed class StockContainerRepository(TuColmadoDbContext dbContext) : IStockContainerRepository +{ + public async Task> GetByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default) + { + var container = await dbContext.StockContainers + .FirstOrDefaultAsync(c => c.Id == id && c.TenantId.Value == tenantId, ct); + + return container is null + ? OperationResult.Bad(DomainError.NotFound("container.not_found")) + : OperationResult.Good(container); + } + + public async Task> GetByPresentationIdAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default) + { + return await dbContext.StockContainers + .Where(c => c.PresentationId == presentationId && c.TenantId.Value == tenantId) + .OrderByDescending(c => c.CreatedAt) + .ToListAsync(ct); + } + + public async Task GetActiveSourceAsync(Guid presentationId, Guid tenantId, CancellationToken ct = default) + { + return await dbContext.StockContainers + .FirstOrDefaultAsync(c => c.PresentationId == presentationId && c.TenantId.Value == tenantId && c.IsActiveSource, ct); + } + + public async Task AddRangeAsync(IEnumerable containers, CancellationToken ct = default) + { + await dbContext.StockContainers.AddRangeAsync(containers, ct); + } + + public async Task NextContainerCodeAsync(Guid tenantId, CancellationToken ct = default) + { + var count = await dbContext.StockContainers + .CountAsync(c => c.TenantId.Value == tenantId, ct); + + return $"C-{(count + 1):D4}"; + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockEntryRepository.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockEntryRepository.cs new file mode 100644 index 0000000..c6b2226 --- /dev/null +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/Repositories/Inventory/StockEntryRepository.cs @@ -0,0 +1,13 @@ +using TuColmadoRD.Core.Application.Inventory.Abstractions; +using TuColmadoRD.Core.Domain.Entities.Inventory; +using TuColmadoRD.Infrastructure.Persistence.Contexts; + +namespace TuColmadoRD.Infrastructure.Persistence.Repositories.Inventory; + +public sealed class StockEntryRepository(TuColmadoDbContext dbContext) : IStockEntryRepository +{ + public async Task AddAsync(StockEntry entry, CancellationToken ct = default) + { + await dbContext.StockEntries.AddAsync(entry, ct); + } +} diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/ServiceRegistration.cs b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/ServiceRegistration.cs index 5bb666e..79c7524 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/ServiceRegistration.cs +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/ServiceRegistration.cs @@ -106,6 +106,11 @@ public static IServiceCollection AddPersistenceInfrastructure(this IServiceColle services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); // Logistics services.AddScoped(); diff --git a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/TuColmadoRD.Infrastructure.Persistence.csproj b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/TuColmadoRD.Infrastructure.Persistence.csproj index efdece1..b96768c 100644 --- a/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/TuColmadoRD.Infrastructure.Persistence.csproj +++ b/backend/src/infrastructure/TuColmadoRD.Infrastructure.Persistence/TuColmadoRD.Infrastructure.Persistence.csproj @@ -22,19 +22,21 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/backend/tests/Presentations/TuColmadoRD.Presentation.API.Tests/TuColmadoRD.Presentation.API.Tests.csproj b/backend/tests/Presentations/TuColmadoRD.Presentation.API.Tests/TuColmadoRD.Presentation.API.Tests.csproj index 2c6b2eb..a853f89 100644 --- a/backend/tests/Presentations/TuColmadoRD.Presentation.API.Tests/TuColmadoRD.Presentation.API.Tests.csproj +++ b/backend/tests/Presentations/TuColmadoRD.Presentation.API.Tests/TuColmadoRD.Presentation.API.Tests.csproj @@ -9,11 +9,11 @@ - - + + - + diff --git a/backend/tests/core/TuColmadoRD.Core.Application.Tests/TuColmadoRD.Core.Application.Tests.csproj b/backend/tests/core/TuColmadoRD.Core.Application.Tests/TuColmadoRD.Core.Application.Tests.csproj index bdbb593..5fe337f 100644 --- a/backend/tests/core/TuColmadoRD.Core.Application.Tests/TuColmadoRD.Core.Application.Tests.csproj +++ b/backend/tests/core/TuColmadoRD.Core.Application.Tests/TuColmadoRD.Core.Application.Tests.csproj @@ -9,11 +9,11 @@ - - + + - + diff --git a/backend/tests/core/TuColmadoRD.Core.Domain.Tests/TuColmadoRD.Core.Domain.Tests.csproj b/backend/tests/core/TuColmadoRD.Core.Domain.Tests/TuColmadoRD.Core.Domain.Tests.csproj index 561421f..8d32bbe 100644 --- a/backend/tests/core/TuColmadoRD.Core.Domain.Tests/TuColmadoRD.Core.Domain.Tests.csproj +++ b/backend/tests/core/TuColmadoRD.Core.Domain.Tests/TuColmadoRD.Core.Domain.Tests.csproj @@ -9,11 +9,11 @@ - - + + - + diff --git a/backend/tests/infrastructure/TuColmadoRD.Infrastructure.Persistence.Tests/TuColmadoRD.Infrastructure.Persistence.Tests.csproj b/backend/tests/infrastructure/TuColmadoRD.Infrastructure.Persistence.Tests/TuColmadoRD.Infrastructure.Persistence.Tests.csproj index d7da177..22dfe42 100644 --- a/backend/tests/infrastructure/TuColmadoRD.Infrastructure.Persistence.Tests/TuColmadoRD.Infrastructure.Persistence.Tests.csproj +++ b/backend/tests/infrastructure/TuColmadoRD.Infrastructure.Persistence.Tests/TuColmadoRD.Infrastructure.Persistence.Tests.csproj @@ -9,15 +9,15 @@ - + - - - + + + - + diff --git a/docker-compose.yml b/docker-compose.yml index cea4611..8e582c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -376,6 +376,15 @@ services: - traefik.http.routers.devops-grafana.tls=true - traefik.http.routers.devops-grafana.tls.certresolver=letsencrypt - traefik.http.services.devops-grafana.loadbalancer.server.port=3000 + - traefik.http.routers.devops-root.rule=Host(`${PUBLIC_DEVOPS_DOMAIN:-devops.tucolmadord.com}`) + - traefik.http.routers.devops-root.entrypoints=websecure + - traefik.http.routers.devops-root.tls=true + - traefik.http.routers.devops-root.tls.certresolver=letsencrypt + - traefik.http.routers.devops-root.middlewares=devops-redirect + - traefik.http.routers.devops-root.service=devops-grafana + - traefik.http.middlewares.devops-redirect.redirectregex.regex=^https://([^/]+)/?$$ + - traefik.http.middlewares.devops-redirect.redirectregex.replacement=https://$${1}/grafana/ + - traefik.http.middlewares.devops-redirect.redirectregex.permanent=true depends_on: - prometheus networks: diff --git a/frontend/landing-page/package-lock.json b/frontend/landing-page/package-lock.json index 5d6285f..74a8027 100644 --- a/frontend/landing-page/package-lock.json +++ b/frontend/landing-page/package-lock.json @@ -8,20 +8,20 @@ "name": "landing-page", "version": "0.0.0", "dependencies": { - "vue": "^3.5.30" + "vue": "^3.5.34" }, "devDependencies": { "@iconify-json/ic": "^1.2.4", "@iconify/tailwind": "^1.2.0", - "@types/node": "^24.12.0", - "@vitejs/plugin-vue": "^6.0.5", + "@types/node": "^25.8.0", + "@vitejs/plugin-vue": "^6.0.7", "@vue/tsconfig": "^0.9.0", - "autoprefixer": "^10.4.27", + "autoprefixer": "^10.5.0", "postcss": "^8.5.8", - "tailwindcss": "3.4.17", - "typescript": "~5.9.3", - "vite": "^8.0.1", - "vue-tsc": "^3.2.5" + "tailwindcss": "^3.4.17", + "typescript": "~6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.9" } }, "node_modules/@alloc/quick-lru": { @@ -56,9 +56,9 @@ } }, "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==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -84,26 +84,24 @@ } }, "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==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, - "peer": 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==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -115,7 +113,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -189,9 +186,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", - "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "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==", "dev": true, "license": "MIT", "optional": true, @@ -246,9 +243,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.122.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", - "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", + "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", "dev": true, "license": "MIT", "funding": { @@ -256,9 +253,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz", + "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==", "cpu": [ "arm64" ], @@ -273,9 +270,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==", "cpu": [ "arm64" ], @@ -290,9 +287,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz", + "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==", "cpu": [ "x64" ], @@ -307,9 +304,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz", + "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==", "cpu": [ "x64" ], @@ -324,9 +321,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", - "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz", + "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==", "cpu": [ "arm" ], @@ -341,9 +338,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz", + "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==", "cpu": [ "arm64" ], @@ -358,9 +355,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz", + "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==", "cpu": [ "arm64" ], @@ -375,9 +372,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz", + "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==", "cpu": [ "ppc64" ], @@ -392,9 +389,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz", + "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==", "cpu": [ "s390x" ], @@ -409,9 +406,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz", + "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==", "cpu": [ "x64" ], @@ -426,9 +423,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz", + "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==", "cpu": [ "x64" ], @@ -443,9 +440,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz", + "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==", "cpu": [ "arm64" ], @@ -460,9 +457,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", - "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz", + "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==", "cpu": [ "wasm32" ], @@ -470,16 +467,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz", + "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==", "cpu": [ "arm64" ], @@ -494,9 +493,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz", + "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==", "cpu": [ "x64" ], @@ -511,16 +510,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "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==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -529,23 +528,23 @@ } }, "node_modules/@types/node": { - "version": "24.12.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", - "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "version": "25.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", + "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", - "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", + "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.0-rc.2" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -585,119 +584,119 @@ } }, "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.34.tgz", + "integrity": "sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.31", + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.34", "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.34.tgz", + "integrity": "sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-core": "3.5.34", + "@vue/shared": "3.5.34" } }, "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", "license": "MIT", "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", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.14", "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.34.tgz", + "integrity": "sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-dom": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/language-core": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.6.tgz", - "integrity": "sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.9.tgz", + "integrity": "sha512-ie0ojt/0fU/GfIogh+zgHbaYRPlt9S+cLOxcWwF7nTSFh897BVgnFKL2byT4kpp1mlqYWZ2psGwSniyE2xsxYw==", "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", - "alien-signals": "^3.0.0", + "alien-signals": "^3.2.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" + "picomatch": "^4.0.4" } }, "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.34.tgz", + "integrity": "sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.31" + "@vue/shared": "3.5.34" } }, "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.34.tgz", + "integrity": "sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/reactivity": "3.5.34", + "@vue/shared": "3.5.34" } }, "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.34.tgz", + "integrity": "sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/runtime-core": "3.5.31", - "@vue/shared": "3.5.31", + "@vue/reactivity": "3.5.34", + "@vue/runtime-core": "3.5.34", + "@vue/shared": "3.5.34", "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==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { - "vue": "3.5.31" + "vue": "3.5.34" } }, "node_modules/@vue/shared": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", - "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.34.tgz", + "integrity": "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==", "license": "MIT" }, "node_modules/@vue/tsconfig": { @@ -720,9 +719,9 @@ } }, "node_modules/alien-signals": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", - "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", "dev": true, "license": "MIT" }, @@ -768,9 +767,9 @@ "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -788,8 +787,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -888,9 +887,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001784", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001784.tgz", - "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==", + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", "dev": true, "funding": [ { @@ -1018,6 +1017,16 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1158,9 +1167,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -1184,13 +1193,13 @@ } }, "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==", + "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.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -1232,6 +1241,16 @@ "node": ">=0.12.0" } }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -1687,9 +1706,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", @@ -1759,9 +1778,9 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dev": true, "funding": [ { @@ -1775,21 +1794,28 @@ ], "license": "MIT", "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { + "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { + "jiti": { + "optional": true + }, "postcss": { "optional": true }, - "ts-node": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } @@ -1899,12 +1925,13 @@ } }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "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" @@ -1931,14 +1958,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", - "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz", + "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.12" + "@oxc-project/types": "=0.130.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -1947,29 +1974,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-x64": "1.0.0-rc.12", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" - } - }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", - "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", - "dev": true, - "license": "MIT" + "@rolldown/binding-android-arm64": "1.0.1", + "@rolldown/binding-darwin-arm64": "1.0.1", + "@rolldown/binding-darwin-x64": "1.0.1", + "@rolldown/binding-freebsd-x64": "1.0.1", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", + "@rolldown/binding-linux-arm64-gnu": "1.0.1", + "@rolldown/binding-linux-arm64-musl": "1.0.1", + "@rolldown/binding-linux-ppc64-gnu": "1.0.1", + "@rolldown/binding-linux-s390x-gnu": "1.0.1", + "@rolldown/binding-linux-x64-gnu": "1.0.1", + "@rolldown/binding-linux-x64-musl": "1.0.1", + "@rolldown/binding-openharmony-arm64": "1.0.1", + "@rolldown/binding-wasm32-wasi": "1.0.1", + "@rolldown/binding-win32-arm64-msvc": "1.0.1", + "@rolldown/binding-win32-x64-msvc": "1.0.1" + } }, "node_modules/run-parallel": { "version": "1.2.0", @@ -2041,9 +2061,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", - "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2055,7 +2075,7 @@ "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.6", + "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", @@ -2064,7 +2084,7 @@ "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", @@ -2078,16 +2098,6 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2112,14 +2122,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -2157,9 +2167,9 @@ "optional": true }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -2171,9 +2181,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "dev": true, "license": "MIT" }, @@ -2216,17 +2226,17 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz", - "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz", + "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.12", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.14", + "rolldown": "1.0.1", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -2242,8 +2252,8 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", - "esbuild": "^0.27.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", @@ -2301,16 +2311,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", - "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", "license": "MIT", "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" + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { "typescript": "*" @@ -2322,14 +2332,14 @@ } }, "node_modules/vue-tsc": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.6.tgz", - "integrity": "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.9.tgz", + "integrity": "sha512-qm8/nbo+9eZc1SCndm9wT+gq23pM+wRIdHY0wjm83B3lIginHTwcdrLUyTrKjDWXbMVNjKegNrnymhpdqnCL3A==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.2.6" + "@vue/language-core": "3.2.9" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -2337,22 +2347,6 @@ "peerDependencies": { "typescript": ">=5.0.0" } - }, - "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } } } } diff --git a/frontend/landing-page/package.json b/frontend/landing-page/package.json index 2debd33..1885d41 100644 --- a/frontend/landing-page/package.json +++ b/frontend/landing-page/package.json @@ -9,19 +9,19 @@ "preview": "vite preview" }, "dependencies": { - "vue": "^3.5.30" + "vue": "^3.5.34" }, "devDependencies": { "@iconify-json/ic": "^1.2.4", "@iconify/tailwind": "^1.2.0", - "@types/node": "^24.12.0", - "@vitejs/plugin-vue": "^6.0.5", + "@types/node": "^25.8.0", + "@vitejs/plugin-vue": "^6.0.7", "@vue/tsconfig": "^0.9.0", - "autoprefixer": "^10.4.27", + "autoprefixer": "^10.5.0", "postcss": "^8.5.8", - "tailwindcss": "3.4.17", - "typescript": "~5.9.3", - "vite": "^8.0.1", - "vue-tsc": "^3.2.5" + "tailwindcss": "^3.4.17", + "typescript": "~6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.9" } } diff --git a/frontend/landing-page/pnpm-lock.yaml b/frontend/landing-page/pnpm-lock.yaml index 8b807d9..e9e5bef 100644 --- a/frontend/landing-page/pnpm-lock.yaml +++ b/frontend/landing-page/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: vue: - specifier: ^3.5.30 - version: 3.5.34(typescript@5.9.3) + specifier: ^3.5.34 + version: 3.5.34(typescript@6.0.3) devDependencies: '@iconify-json/ic': specifier: ^1.2.4 @@ -19,39 +19,35 @@ importers: specifier: ^1.2.0 version: 1.2.0 '@types/node': - specifier: ^24.12.0 - version: 24.12.3 + specifier: ^25.8.0 + version: 25.8.0 '@vitejs/plugin-vue': - specifier: ^6.0.5 - version: 6.0.6(vite@8.0.11(@types/node@24.12.3)(jiti@1.21.7)(yaml@2.8.4))(vue@3.5.34(typescript@5.9.3)) + specifier: ^6.0.7 + version: 6.0.7(vite@8.0.13(@types/node@25.8.0)(jiti@1.21.7)(yaml@2.8.4))(vue@3.5.34(typescript@6.0.3)) '@vue/tsconfig': specifier: ^0.9.0 - version: 0.9.1(typescript@5.9.3)(vue@3.5.34(typescript@5.9.3)) + version: 0.9.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)) autoprefixer: - specifier: ^10.4.27 + specifier: ^10.5.0 version: 10.5.0(postcss@8.5.14) postcss: specifier: ^8.5.8 version: 8.5.14 tailwindcss: - specifier: 3.4.17 - version: 3.4.17 + specifier: 4.3.0 + version: 4.3.0 typescript: - specifier: ~5.9.3 - version: 5.9.3 + specifier: ~6.0.3 + version: 6.0.3 vite: - specifier: ^8.0.1 - version: 8.0.11(@types/node@24.12.3)(jiti@1.21.7)(yaml@2.8.4) + specifier: ^8.0.13 + version: 8.0.13(@types/node@25.8.0)(jiti@1.21.7)(yaml@2.8.4) vue-tsc: - specifier: ^3.2.5 - version: 3.2.8(typescript@5.9.3) + specifier: ^3.2.9 + version: 3.2.9(typescript@6.0.3) packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -87,149 +83,118 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@oxc-project/types@0.130.0': + resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} - '@oxc-project/types@0.128.0': - resolution: {integrity: sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==} - - '@rolldown/binding-android-arm64@1.0.0-rc.18': - resolution: {integrity: sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==} + '@rolldown/binding-android-arm64@1.0.1': + resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.18': - resolution: {integrity: sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==} + '@rolldown/binding-darwin-arm64@1.0.1': + resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.18': - resolution: {integrity: sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==} + '@rolldown/binding-darwin-x64@1.0.1': + resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.18': - resolution: {integrity: sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==} + '@rolldown/binding-freebsd-x64@1.0.1': + resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': - resolution: {integrity: sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': - resolution: {integrity: sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==} + '@rolldown/binding-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': - resolution: {integrity: sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==} + '@rolldown/binding-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': - resolution: {integrity: sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.1': + resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18': - resolution: {integrity: sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==} + '@rolldown/binding-linux-s390x-gnu@1.0.1': + resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18': - resolution: {integrity: sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==} + '@rolldown/binding-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': - resolution: {integrity: sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==} + '@rolldown/binding-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': - resolution: {integrity: sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==} + '@rolldown/binding-openharmony-arm64@1.0.1': + resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': - resolution: {integrity: sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==} + '@rolldown/binding-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': - resolution: {integrity: sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==} + '@rolldown/binding-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': - resolution: {integrity: sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==} + '@rolldown/binding-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.13': - resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} - - '@rolldown/pluginutils@1.0.0-rc.18': - resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@types/node@24.12.3': - resolution: {integrity: sha512-8oljBDGun9cIsZRJR6fkihn0TSXJI0UDOOhncYaERq6M0JMDoPLxyscwruJcb4GKS6dvK/d8xebYBg27h/duaQ==} + '@types/node@25.8.0': + resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} - '@vitejs/plugin-vue@6.0.6': - resolution: {integrity: sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==} + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -256,8 +221,8 @@ packages: '@vue/compiler-ssr@3.5.34': resolution: {integrity: sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==} - '@vue/language-core@3.2.8': - resolution: {integrity: sha512-9OiSPQFiAAWNVnXb0d2dcTmcKnFQamhuNES6ayyISrb/mwPWVgoGdAqSfCWqKhQpa3D5gDTcYD+w7ObiheZ81g==} + '@vue/language-core@3.2.9': + resolution: {integrity: sha512-ie0ojt/0fU/GfIogh+zgHbaYRPlt9S+cLOxcWwF7nTSFh897BVgnFKL2byT4kpp1mlqYWZ2psGwSniyE2xsxYw==} '@vue/reactivity@3.5.34': resolution: {integrity: sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==} @@ -287,18 +252,8 @@ packages: vue: optional: true - alien-signals@3.1.2: - resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} autoprefixer@10.5.0: resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} @@ -307,44 +262,19 @@ packages: peerDependencies: postcss: ^8.1.0 - baseline-browser-mapping@2.10.27: - resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==} + baseline-browser-mapping@2.10.30: + resolution: {integrity: sha512-xjOFN16Ha1+Rz4nFYKqHU/LSB+gx/Vi3yQLX7r7sAW+Wa+8hhF2h4pvqTrTMc8+WcDBEunnUurr46Jvv0jk3Vg==} engines: {node: '>=6.0.0'} hasBin: true - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - caniuse-lite@1.0.30001792: resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -352,23 +282,13 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - - electron-to-chromium@1.5.352: - resolution: {integrity: sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==} + electron-to-chromium@1.5.357: + resolution: {integrity: sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==} entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -376,13 +296,6 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -392,10 +305,6 @@ packages: picomatch: optional: true - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -404,41 +313,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - jiti@1.21.7: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true @@ -478,28 +352,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -517,109 +387,30 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-releases@2.0.38: - resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + node-releases@2.0.44: + resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 - - postcss-js@4.1.0: - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 - - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} - postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -627,79 +418,32 @@ packages: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} - hasBin: true - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rolldown@1.0.0-rc.18: - resolution: {integrity: sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==} + rolldown@1.0.1: + resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} - engines: {node: '>=14.0.0'} - hasBin: true - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} @@ -707,11 +451,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vite@8.0.11: - resolution: {integrity: sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==} + vite@8.0.13: + resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -756,8 +497,8 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - vue-tsc@3.2.8: - resolution: {integrity: sha512-27vTLJ6Q2370obOd0PFYoYoKnmXJ521uUIedrs3Zhhhg/8YG10VOCMmwt+JQslatpAMTDbnWiitLnoD5VlIvog==} + vue-tsc@3.2.9: + resolution: {integrity: sha512-qm8/nbo+9eZc1SCndm9wT+gq23pM+wRIdHY0wjm83B3lIginHTwcdrLUyTrKjDWXbMVNjKegNrnymhpdqnCL3A==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -777,8 +518,6 @@ packages: snapshots: - '@alloc/quick-lru@5.2.0': {} - '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -818,20 +557,8 @@ snapshots: '@iconify/types@2.0.0': {} - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -839,87 +566,73 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@oxc-project/types@0.128.0': {} + '@oxc-project/types@0.130.0': {} - '@rolldown/binding-android-arm64@1.0.0-rc.18': + '@rolldown/binding-android-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.18': + '@rolldown/binding-darwin-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.18': + '@rolldown/binding-darwin-x64@1.0.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.18': + '@rolldown/binding-freebsd-x64@1.0.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': + '@rolldown/binding-linux-arm64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': + '@rolldown/binding-linux-arm64-musl@1.0.1': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': + '@rolldown/binding-linux-ppc64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18': + '@rolldown/binding-linux-s390x-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18': + '@rolldown/binding-linux-x64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': + '@rolldown/binding-linux-x64-musl@1.0.1': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': + '@rolldown/binding-openharmony-arm64@1.0.1': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': + '@rolldown/binding-wasm32-wasi@1.0.1': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': + '@rolldown/binding-win32-arm64-msvc@1.0.1': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': + '@rolldown/binding-win32-x64-msvc@1.0.1': optional: true - '@rolldown/pluginutils@1.0.0-rc.13': {} - - '@rolldown/pluginutils@1.0.0-rc.18': {} + '@rolldown/pluginutils@1.0.1': {} '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@types/node@24.12.3': + '@types/node@25.8.0': dependencies: - undici-types: 7.16.0 + undici-types: 7.24.6 - '@vitejs/plugin-vue@6.0.6(vite@8.0.11(@types/node@24.12.3)(jiti@1.21.7)(yaml@2.8.4))(vue@3.5.34(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.7(vite@8.0.13(@types/node@25.8.0)(jiti@1.21.7)(yaml@2.8.4))(vue@3.5.34(typescript@6.0.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-rc.13 - vite: 8.0.11(@types/node@24.12.3)(jiti@1.21.7)(yaml@2.8.4) - vue: 3.5.34(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.13(@types/node@25.8.0)(jiti@1.21.7)(yaml@2.8.4) + vue: 3.5.34(typescript@6.0.3) '@volar/language-core@2.4.28': dependencies: @@ -963,12 +676,12 @@ snapshots: '@vue/compiler-dom': 3.5.34 '@vue/shared': 3.5.34 - '@vue/language-core@3.2.8': + '@vue/language-core@3.2.9': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.34 '@vue/shared': 3.5.34 - alien-signals: 3.1.2 + alien-signals: 3.2.1 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.4 @@ -989,29 +702,20 @@ snapshots: '@vue/shared': 3.5.34 csstype: 3.2.3 - '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3))': + '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@6.0.3))': dependencies: '@vue/compiler-ssr': 3.5.34 '@vue/shared': 3.5.34 - vue: 3.5.34(typescript@5.9.3) + vue: 3.5.34(typescript@6.0.3) '@vue/shared@3.5.34': {} - '@vue/tsconfig@0.9.1(typescript@5.9.3)(vue@3.5.34(typescript@5.9.3))': + '@vue/tsconfig@0.9.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3))': optionalDependencies: - typescript: 5.9.3 - vue: 3.5.34(typescript@5.9.3) + typescript: 6.0.3 + vue: 3.5.34(typescript@6.0.3) - alien-signals@3.1.2: {} - - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - - arg@5.0.2: {} + alien-signals@3.2.1: {} autoprefixer@10.5.0(postcss@8.5.14): dependencies: @@ -1022,116 +726,41 @@ snapshots: postcss: 8.5.14 postcss-value-parser: 4.2.0 - baseline-browser-mapping@2.10.27: {} - - binary-extensions@2.3.0: {} - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 + baseline-browser-mapping@2.10.30: {} browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.27 + baseline-browser-mapping: 2.10.30 caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.352 - node-releases: 2.0.38 + electron-to-chromium: 1.5.357 + node-releases: 2.0.44 update-browserslist-db: 1.2.3(browserslist@4.28.2) - camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001792: {} - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - commander@4.1.1: {} - - cssesc@3.0.0: {} - csstype@3.2.3: {} detect-libc@2.1.2: {} - didyoumean@1.2.2: {} - - dlv@1.1.3: {} - - electron-to-chromium@1.5.352: {} + electron-to-chromium@1.5.357: {} entities@7.0.1: {} - es-errors@1.3.0: {} - escalade@3.2.0: {} estree-walker@2.0.2: {} - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - fraction.js@5.3.4: {} fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - hasown@2.0.3: - dependencies: - function-bind: 1.1.2 - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.16.2: - dependencies: - hasown: 2.0.3 - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - jiti@1.21.7: {} + jiti@1.21.7: + optional: true lightningcss-android-arm64@1.32.0: optional: true @@ -1182,82 +811,22 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - lilconfig@3.1.3: {} - - lines-and-columns@1.2.4: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - muggle-string@0.4.1: {} - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - nanoid@3.3.12: {} - node-releases@2.0.38: {} - - normalize-path@3.0.0: {} - - object-assign@4.1.1: {} - - object-hash@3.0.0: {} + node-releases@2.0.44: {} path-browserify@1.0.1: {} - path-parse@1.0.7: {} - picocolors@1.1.1: {} - picomatch@2.3.2: {} - picomatch@4.0.4: {} - pify@2.3.0: {} - - pirates@4.0.7: {} - - postcss-import@15.1.0(postcss@8.5.14): - dependencies: - postcss: 8.5.14 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.12 - - postcss-js@4.1.0(postcss@8.5.14): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.14 - - postcss-load-config@4.0.2(postcss@8.5.14): - dependencies: - lilconfig: 3.1.3 - yaml: 2.8.4 - optionalDependencies: - postcss: 8.5.14 - - postcss-nested@6.2.0(postcss@8.5.14): - dependencies: - postcss: 8.5.14 - postcss-selector-parser: 6.1.2 - - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - postcss-value-parser@4.2.0: {} postcss@8.5.14: @@ -1266,116 +835,42 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - queue-microtask@1.2.3: {} - - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.2 - - resolve@1.22.12: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.1.0: {} - - rolldown@1.0.0-rc.18: + rolldown@1.0.1: dependencies: - '@oxc-project/types': 0.128.0 - '@rolldown/pluginutils': 1.0.0-rc.18 + '@oxc-project/types': 0.130.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.18 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.18 - '@rolldown/binding-darwin-x64': 1.0.0-rc.18 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.18 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.18 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.18 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.18 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.18 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.18 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.18 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.18 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.18 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.18 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.18 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.18 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 + '@rolldown/binding-android-arm64': 1.0.1 + '@rolldown/binding-darwin-arm64': 1.0.1 + '@rolldown/binding-darwin-x64': 1.0.1 + '@rolldown/binding-freebsd-x64': 1.0.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.1 + '@rolldown/binding-linux-arm64-musl': 1.0.1 + '@rolldown/binding-linux-ppc64-gnu': 1.0.1 + '@rolldown/binding-linux-s390x-gnu': 1.0.1 + '@rolldown/binding-linux-x64-gnu': 1.0.1 + '@rolldown/binding-linux-x64-musl': 1.0.1 + '@rolldown/binding-openharmony-arm64': 1.0.1 + '@rolldown/binding-wasm32-wasi': 1.0.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.1 + '@rolldown/binding-win32-x64-msvc': 1.0.1 source-map-js@1.2.1: {} - sucrase@3.35.1: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - tinyglobby: 0.2.16 - ts-interface-checker: 0.1.13 - - supports-preserve-symlinks-flag@1.0.0: {} - - tailwindcss@3.4.17: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.14 - postcss-import: 15.1.0(postcss@8.5.14) - postcss-js: 4.1.0(postcss@8.5.14) - postcss-load-config: 4.0.2(postcss@8.5.14) - postcss-nested: 6.2.0(postcss@8.5.14) - postcss-selector-parser: 6.1.2 - resolve: 1.22.12 - sucrase: 3.35.1 - transitivePeerDependencies: - - ts-node - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 + tailwindcss@4.3.0: {} tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - ts-interface-checker@0.1.13: {} - tslib@2.8.1: optional: true - typescript@5.9.3: {} + typescript@6.0.3: {} - undici-types@7.16.0: {} + undici-types@7.24.6: {} update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: @@ -1383,37 +878,36 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - util-deprecate@1.0.2: {} - - vite@8.0.11(@types/node@24.12.3)(jiti@1.21.7)(yaml@2.8.4): + vite@8.0.13(@types/node@25.8.0)(jiti@1.21.7)(yaml@2.8.4): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 postcss: 8.5.14 - rolldown: 1.0.0-rc.18 + rolldown: 1.0.1 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 24.12.3 + '@types/node': 25.8.0 fsevents: 2.3.3 jiti: 1.21.7 yaml: 2.8.4 vscode-uri@3.1.0: {} - vue-tsc@3.2.8(typescript@5.9.3): + vue-tsc@3.2.9(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.28 - '@vue/language-core': 3.2.8 - typescript: 5.9.3 + '@vue/language-core': 3.2.9 + typescript: 6.0.3 - vue@3.5.34(typescript@5.9.3): + vue@3.5.34(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.34 '@vue/compiler-sfc': 3.5.34 '@vue/runtime-dom': 3.5.34 - '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3)) + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@6.0.3)) '@vue/shared': 3.5.34 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 - yaml@2.8.4: {} + yaml@2.8.4: + optional: true diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d59ce25..0383e43 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,267 +1,269 @@ -{ - "name": "TuColmadoRD.Frontend", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "devDependencies": { - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.13", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.13.tgz", - "integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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/caniuse-lite": { - "version": "1.0.30001784", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001784.tgz", - "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==", - "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/electron-to-chromium": { - "version": "1.5.331", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz", - "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==", - "dev": true, - "license": "ISC" - }, - "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/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", - "dev": true, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tailwindcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", - "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", - "dev": true, - "license": "MIT" - }, - "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" - } - } - } -} +{ + "name": "TuColmadoRD.Frontend", + "version": "0.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "version": "0.3.0", + "devDependencies": { + "autoprefixer": "^10.5.0", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.13.tgz", + "integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "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/electron-to-chromium": { + "version": "1.5.331", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz", + "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==", + "dev": true, + "license": "ISC" + }, + "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/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "dev": true, + "license": "MIT" + }, + "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" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json index f503a5c..e12c034 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,9 +1,9 @@ { "version": "0.3.0", "devDependencies": { - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2" + "autoprefixer": "^10.5.0", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0" } } diff --git a/frontend/web-admin/package-lock.json b/frontend/web-admin/package-lock.json index f097c54..a289685 100644 --- a/frontend/web-admin/package-lock.json +++ b/frontend/web-admin/package-lock.json @@ -8,34 +8,33 @@ "name": "web-admin", "version": "0.0.1-test.3", "dependencies": { - "@angular/common": "^21.2.0", - "@angular/compiler": "^21.2.0", - "@angular/core": "^21.2.0", - "@angular/forms": "^21.2.0", - "@angular/platform-browser": "^21.2.0", - "@angular/router": "^21.2.0", + "@angular/common": "^21.2.13", + "@angular/compiler": "^21.2.13", + "@angular/core": "^21.2.13", + "@angular/forms": "^21.2.13", + "@angular/platform-browser": "^21.2.13", + "@angular/router": "^21.2.13", "maplibre-gl": "^5.24.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, "devDependencies": { - "@angular/build": "^21.2.6", - "@angular/cli": "^21.2.6", - "@angular/compiler-cli": "^21.2.0", + "@angular/build": "^21.2.11", + "@angular/cli": "^21.2.11", + "@angular/compiler-cli": "^21.2.13", "@iconify-json/ic": "^1.2.4", "@iconify/tailwind": "^1.2.0", - "@playwright/test": "^1.59.1", - "@tailwindcss/postcss": "^4.2.2", - "autoprefixer": "^10.4.27", + "@playwright/test": "^1.60.0", + "autoprefixer": "^10.5.0", "daisyui": "^4.12.24", "electron": "^41.1.1", "electron-builder": "^26.8.1", "javascript-obfuscator": "^5.4.1", "jsdom": "^28.0.0", - "postcss": "^8.5.8", + "postcss": "^8.5.14", "prettier": "^3.8.1", "selenium-webdriver": "^4.34.0", - "tailwindcss": "^3.4.19", + "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "typescript": "~5.9.2", "vitest": "^4.0.8" @@ -285,13 +284,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.6.tgz", - "integrity": "sha512-h4qybKypR7OuwcTHPQI1zRm7abXgmPiV49vI2UeMtVVY/GKzru9gMexcYmWabzEyBY8w6VSfWjV2X+eit2EhDQ==", + "version": "0.2102.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.11.tgz", + "integrity": "sha512-t7J8aaUho1mXjiIecPNX5/rjXeV8j8ZCGY5tD3ic5kzKxPkbuYYcQpJLdzlmBcN+wDgCmNdo8ySvItvU0m58lg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.6", + "@angular-devkit/core": "21.2.11", "rxjs": "7.8.2" }, "bin": { @@ -304,9 +303,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.6.tgz", - "integrity": "sha512-u5gPTAY7MC02uACQE39xxiFcm1hslF+ih/f2borMWnhER0JNTpHjLiLRXFkq7or7+VVHU30zfhK4XNAuO4WTIg==", + "version": "21.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.11.tgz", + "integrity": "sha512-kfMNh5X2hOdyr0uNFaaHUJR3OVr4oH2+UhI+FsTu7gqogdgYlHAVHhHAFulfDgtAEOiqpeSQF9RhQnCJl+/LXA==", "dev": true, "license": "MIT", "dependencies": { @@ -332,13 +331,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.6.tgz", - "integrity": "sha512-hk2duJlPJyiMaI9MVWA5XpmlpD9C4n8qgquV/MJ7/n+ZRSwW3w1ndL5qUmA1ki+4Da54v/Rc8Wt5tUS955+93w==", + "version": "21.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.11.tgz", + "integrity": "sha512-69CWZ5/ftLdpUPAwwdAxTNosiGXUyvwdnOfmHsd9NvCT0OSTeq0eQ0UfnGcHASrXIVmnyWiNfBWM1DLqsgBXmw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.6", + "@angular-devkit/core": "21.2.11", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -351,14 +350,14 @@ } }, "node_modules/@angular/build": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.6.tgz", - "integrity": "sha512-PJltYl9/INfz8nZ/KHf39nqlmt3c9PR0jJaZt6hhCPENyAf4PwQpm28erkJmbOYO864goIuws41lduYXyDqQ0Q==", + "version": "21.2.11", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.11.tgz", + "integrity": "sha512-2afR6VKkP0HH2u6OuijSMgSHsL5tU4CBCixgQtY677mlvS8TOZg/kOksJIUlz0EvDVCJZBK8WLH9cPJ6mC/Qdg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.6", + "@angular-devkit/architect": "0.2102.11", "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -382,7 +381,7 @@ "source-map-support": "0.5.21", "tinyglobby": "0.2.15", "undici": "7.24.4", - "vite": "7.3.1", + "vite": "7.3.2", "watchpack": "2.5.1" }, "engines": { @@ -401,7 +400,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.6", + "@angular/ssr": "^21.2.11", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -451,19 +450,19 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.6.tgz", - "integrity": "sha512-I5DOFcIT1HKymyy2f78fjgD0Iv6jG46GbBZ/VxejcnhjubFpuN4CwPdugXf9rIDs8KZQqBzDBFUbq11vnk8h0A==", + "version": "21.2.11", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.11.tgz", + "integrity": "sha512-vpF/oa+HzLl4lF78ePCgkhBdQj29IlFvZtBsbAXXpb16FLZSua2m7+yHd/PICTlchh1+LfIxFY9snMY1BllBsQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.6", - "@angular-devkit/core": "21.2.6", - "@angular-devkit/schematics": "21.2.6", + "@angular-devkit/architect": "0.2102.11", + "@angular-devkit/core": "21.2.11", + "@angular-devkit/schematics": "21.2.11", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.6", + "@schematics/angular": "21.2.11", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.48.1", "ini": "6.0.0", @@ -486,9 +485,9 @@ } }, "node_modules/@angular/common": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.7.tgz", - "integrity": "sha512-YFdnU5z8JloJjLYa52OyCOULQhqEE/ym7vKfABySWDsiVXZr9FNmKMeZi/lUcg7ZO22UbBihqW9a9D6VSHOo+g==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.13.tgz", + "integrity": "sha512-fNvRmGAX0zbsLX/kJjgb6l8HAuGTpfYRNc06taTCIvED2RsRpfwrh79IxYlPBspr+hpFbHa0/kxU6Q5I8V0jKQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -497,14 +496,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.7", + "@angular/core": "21.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.7.tgz", - "integrity": "sha512-4J0Nl5gGmr5SKgR3FHK4J6rdG0aP5zAsY3AJU8YXH+D98CeNTjQUD8XHsdD2cTwo08V5mDdFa5VCsREpMPJ5gQ==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.13.tgz", + "integrity": "sha512-0OZk5ujHgowRme3iXJ1Ce1OI3eTDcGovBARBiyJT0E8kt9Y0TdQdGaYMRrNN1UzDv4hk8f1d/xVeF0BpMTvqPQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -514,9 +513,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.7.tgz", - "integrity": "sha512-r76vKBM7Wu0N8PTeec7340Gtv1wC7IBQGJOQnukshPgzaabgNKxmUiChGxi+RJNo/Tsdiw9ZfddcBgBjq79ZIg==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.13.tgz", + "integrity": "sha512-ueETJy2ZcXZ4a0aLEr+oPMw26f8Hn903WC4QN0MCH+sLB9Zustpzydqtmzo5mdSzwuoLoxcesYJTZFmpwD1xIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -537,7 +536,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.7", + "@angular/compiler": "21.2.13", "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { @@ -547,9 +546,9 @@ } }, "node_modules/@angular/core": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.7.tgz", - "integrity": "sha512-4bnskeRNNOZMn3buVw47Zz9Py4B8AZgYHe5xBEMOY5/yrldb7OFje5gWCWls23P18FKwhl+Xx1hgnOEPSs29gw==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.13.tgz", + "integrity": "sha512-23tS4oNL8nvkHcI4l9rbruQs2WS4yqQmBVQxWakqS9cmRpArLGgveR+hKNU5tPXm5EAi8oLO34/Zy7z70jUpCg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -558,7 +557,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.7", + "@angular/compiler": "21.2.13", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -572,9 +571,9 @@ } }, "node_modules/@angular/forms": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.7.tgz", - "integrity": "sha512-YD/h07cdEeAUs41ysTk6820T0lG/XiQmFiq02d3IsiHYI5Vaj2pg9Ti1wWZYEBM//hVAPTzV0dwdV7Q1Gxju1w==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.13.tgz", + "integrity": "sha512-efAKdL8eVRlGvcJWrUFcYyRE/togWfopUTw2D5TIkDAndnmmRaWA70wD4n/E1FFV5UdxSBxoyEYE0qVlPiewtQ==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -584,16 +583,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.7", - "@angular/core": "21.2.7", - "@angular/platform-browser": "21.2.7", + "@angular/common": "21.2.13", + "@angular/core": "21.2.13", + "@angular/platform-browser": "21.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.7.tgz", - "integrity": "sha512-nklVhstRZL4wpYg9Cyae/Eyfa7LMpgb0TyD/F//qCuohhM8nM7F+O0ekykGD6H+I34jsvqx6yLS7MicndWVz7Q==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.13.tgz", + "integrity": "sha512-96rcwLHsklqAYRuS2SEBOUdQS5PLkuUIEEIjpYu4rxU2PVvOMapJEImM/QBxrbwjnCgRbj/CivkgfjiR0R0wSA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -602,9 +601,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.7", - "@angular/common": "21.2.7", - "@angular/core": "21.2.7" + "@angular/animations": "21.2.13", + "@angular/common": "21.2.13", + "@angular/core": "21.2.13" }, "peerDependenciesMeta": { "@angular/animations": { @@ -613,9 +612,9 @@ } }, "node_modules/@angular/router": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.7.tgz", - "integrity": "sha512-Ina6XgtpvXT1OsLAomURHJGQDOkIVGrguWAOZ7+gOjsJEjUfpxTktFter+/K59KMC2yv6yneLvYSn3AswTYx7A==", + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.13.tgz", + "integrity": "sha512-/JXtdhUH/rDGiJmUNrrbs52Aji4sygVCz5HIBujrnj3cjreKam7n98Ufkh0aZvAKybdGd5A8srNUFePzAvfExQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -624,9 +623,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.7", - "@angular/core": "21.2.7", - "@angular/platform-browser": "21.2.7", + "@angular/common": "21.2.13", + "@angular/core": "21.2.13", + "@angular/platform-browser": "21.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -2295,6 +2294,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" @@ -2307,6 +2307,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2318,6 +2319,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2801,9 +2803,9 @@ "optional": true }, "node_modules/@hono/node-server": { - "version": "1.19.12", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.12.tgz", - "integrity": "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==", + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "dev": true, "license": "MIT", "engines": { @@ -4746,13 +4748,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", - "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.59.1" + "playwright": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -5340,14 +5342,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.6.tgz", - "integrity": "sha512-KpLD8R2S762jbLdNEepE+b7KjhVOKPFHHdgNqhPv0NiGLdsvXSOx1e63JvFacoCZdmP7n3/gwmyT/utcVvnsag==", + "version": "21.2.11", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.11.tgz", + "integrity": "sha512-EqH12Fr3vaWFpsilFDFXkxwMIidEDZr5cGl0w2hDRG7DjXE2oRB/VXix8xmpuHkzJ40Jgew6hIc+bfbwQhFK1A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.6", - "@angular-devkit/schematics": "21.2.6", + "@angular-devkit/core": "21.2.11", + "@angular-devkit/schematics": "21.2.11", "jsonc-parser": "3.3.1" }, "engines": { @@ -5468,291 +5470,6 @@ "node": ">=10" } }, - "node_modules/@tailwindcss/node": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", - "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.2" - } - }, - "node_modules/@tailwindcss/node/node_modules/tailwindcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", - "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", - "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.2", - "@tailwindcss/oxide-darwin-arm64": "4.2.2", - "@tailwindcss/oxide-darwin-x64": "4.2.2", - "@tailwindcss/oxide-freebsd-x64": "4.2.2", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", - "@tailwindcss/oxide-linux-x64-musl": "4.2.2", - "@tailwindcss/oxide-wasm32-wasi": "4.2.2", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", - "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", - "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", - "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", - "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", - "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", - "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", - "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", - "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", - "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", - "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", - "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", - "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz", - "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.2", - "@tailwindcss/oxide": "4.2.2", - "postcss": "^8.5.6", - "tailwindcss": "4.2.2" - } - }, - "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", - "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", @@ -6111,9 +5828,9 @@ "license": "MIT" }, "node_modules/@xmldom/xmldom": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", - "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", "dev": true, "license": "MIT", "engines": { @@ -6692,9 +6409,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -6712,8 +6429,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -7229,9 +6946,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001784", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001784.tgz", - "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==", + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", "dev": true, "funding": [ { @@ -8728,20 +8445,6 @@ "once": "^1.4.0" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -9111,13 +8814,13 @@ } }, "node_modules/express-rate-limit": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", - "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "10.1.0" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -9794,9 +9497,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -9807,9 +9510,9 @@ } }, "node_modules/hono": { - "version": "4.12.10", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.10.tgz", - "integrity": "sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==", + "version": "4.12.19", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.19.tgz", + "integrity": "sha512-xa3eYXYXx68XTT4hZ7dRzsXBhaq85ToSrlUJNoR0gwz/1Ap/CNwX47wfvV7pc/xWhjKVVkLT7zBJy8chhNguqQ==", "dev": true, "license": "MIT", "engines": { @@ -10208,9 +9911,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -10295,13 +9998,13 @@ } }, "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==", + "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.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -10965,267 +10668,6 @@ "immediate": "~3.0.5" } }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": 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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "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" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -12799,13 +12241,13 @@ } }, "node_modules/playwright": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", - "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.59.1" + "playwright-core": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -12818,9 +12260,9 @@ } }, "node_modules/playwright-core": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", - "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -12871,9 +12313,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "dev": true, "funding": [ { @@ -13419,12 +12861,13 @@ } }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "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" @@ -14340,9 +13783,9 @@ "license": "MIT" }, "node_modules/stdin-discarder": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz", - "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", + "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==", "dev": true, "license": "MIT", "engines": { @@ -14692,20 +14135,6 @@ "node": ">=8.10.0" } }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/tar": { "version": "7.5.13", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", @@ -15265,9 +14694,9 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/web-admin/package.json b/frontend/web-admin/package.json index d50b3ac..5ccf398 100644 --- a/frontend/web-admin/package.json +++ b/frontend/web-admin/package.json @@ -23,34 +23,33 @@ "private": true, "packageManager": "npm@11.8.0", "dependencies": { - "@angular/common": "^21.2.0", - "@angular/compiler": "^21.2.0", - "@angular/core": "^21.2.0", - "@angular/forms": "^21.2.0", - "@angular/platform-browser": "^21.2.0", - "@angular/router": "^21.2.0", + "@angular/common": "^21.2.13", + "@angular/compiler": "^21.2.13", + "@angular/core": "^21.2.13", + "@angular/forms": "^21.2.13", + "@angular/platform-browser": "^21.2.13", + "@angular/router": "^21.2.13", "maplibre-gl": "^5.24.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, "devDependencies": { - "@angular/build": "^21.2.6", - "@angular/cli": "^21.2.6", - "@angular/compiler-cli": "^21.2.0", + "@angular/build": "^21.2.11", + "@angular/cli": "^21.2.11", + "@angular/compiler-cli": "^21.2.13", "@iconify-json/ic": "^1.2.4", "@iconify/tailwind": "^1.2.0", - "@playwright/test": "^1.59.1", - "@tailwindcss/postcss": "^4.2.2", - "autoprefixer": "^10.4.27", + "@playwright/test": "^1.60.0", + "autoprefixer": "^10.5.0", "daisyui": "^4.12.24", "electron": "^41.1.1", "electron-builder": "^26.8.1", "javascript-obfuscator": "^5.4.1", "jsdom": "^28.0.0", - "postcss": "^8.5.8", + "postcss": "^8.5.14", "prettier": "^3.8.1", "selenium-webdriver": "^4.34.0", - "tailwindcss": "^3.4.19", + "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "typescript": "~5.9.2", "vitest": "^4.0.8" diff --git a/frontend/web-admin/playwright.local.config.ts b/frontend/web-admin/playwright.local.config.ts new file mode 100644 index 0000000..875a591 --- /dev/null +++ b/frontend/web-admin/playwright.local.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from '@playwright/test'; +export default defineConfig({ + testDir: './e2e', + fullyParallel: false, + retries: 0, + workers: 1, + timeout: 60_000, + use: { + baseURL: 'http://localhost:4200', + trace: 'off', + video: 'off', + screenshot: 'only-on-failure', + headless: true, + locale: 'es-DO', + }, +}); diff --git a/frontend/web-admin/src/app/app.routes.ts b/frontend/web-admin/src/app/app.routes.ts index 6b2df84..5f15c53 100644 --- a/frontend/web-admin/src/app/app.routes.ts +++ b/frontend/web-admin/src/app/app.routes.ts @@ -57,6 +57,18 @@ export const routes: Routes = [ path: 'inventory', loadComponent: () => import('./features/portal/inventory/inventory').then(m => m.Inventory) }, + { + path: 'presentations/:id', + loadComponent: () => import('./features/portal/presentations/presentations').then(m => m.Presentations) + }, + { + path: 'stock-entries', + loadComponent: () => import('./features/portal/stock-entries/stock-entries').then(m => m.StockEntries) + }, + { + path: 'monetary-fund', + loadComponent: () => import('./features/portal/monetary-fund/monetary-fund').then(m => m.MonetaryFund) + }, { path: 'categories', loadComponent: () => import('./features/portal/categories/categories').then(m => m.Categories) diff --git a/frontend/web-admin/src/app/core/constants.ts b/frontend/web-admin/src/app/core/constants.ts new file mode 100644 index 0000000..ee18369 --- /dev/null +++ b/frontend/web-admin/src/app/core/constants.ts @@ -0,0 +1,220 @@ +export const LS_KEYS = { + TOKEN: 'tc_token', + USER: 'tc_user', + TENANT: 'tc_tenant', + THEME: 'tucolmado-theme', + DOWNLOAD_BANNER_DISMISSED: 'tc_download_banner_dismissed', +} as const; + +export const PAYMENT_METHOD = { + CASH: 1, + CARD: 2, + TRANSFER: 3, + CREDIT: 4, + DELIVERY: 5, +} as const; + +export const PAYMENT_METHOD_LABELS: Record = { + 1: 'Efectivo', + 2: 'Tarjeta', + 3: 'Transferencia', + 4: 'Crédito', + 5: 'Delivery', +} as const; + +export const PRESENTATION_TYPE = { + BULK_CONTAINER: 1, + PACKAGED_UNIT: 2, +} as const; + +export const PRESENTATION_TYPE_LABELS: Record = { + 1: 'Contenedor a granel', + 2: 'Unidad empacada', +} as const; + +export const SELL_MODE = { + BY_UNIT: 1, + BY_WEIGHT: 2, + BY_CONTAINER: 3, +} as const; + +export const SELL_MODE_LABELS: Record = { + 1: 'Por unidad', + 2: 'Por peso', + 3: 'Por contenedor', +} as const; + +export const CONTAINER_STATUS = { + SEALED: 1, + OPEN: 2, + EMPTY: 3, +} as const; + +export const CONTAINER_STATUS_LABELS: Record = { + 1: 'Sellado', + 2: 'Abierto', + 3: 'Vacío', +} as const; + +export const FUND_TRANSACTION_TYPE = { + DEPOSIT: 1, + EXPENSE: 2, +} as const; + +export const FUND_TRANSACTION_TYPE_LABELS: Record = { + 1: 'Depósito', + 2: 'Gasto', +} as const; + +export const EXPENSE_CATEGORY = { + STOCK_PURCHASE: 1, + OPERATIONAL: 2, + LOSS: 3, + EXTERNAL_FUND: 4, + OTHER: 5, +} as const; + +export const EXPENSE_CATEGORY_LABELS: Record = { + 1: 'Compra de inventario', + 2: 'Operacional', + 3: 'Pérdida', + 4: 'Fondo externo', + 5: 'Otro', +} as const; + +export const UNIT_OF_MEASURE = { + POUND: 1, + OUNCE: 2, + KILOGRAM: 3, + UNIT: 10, + BOX: 11, + PACKAGE: 12, + SACK: 13, + LITER: 20, + GALLON: 21, + BOTTLE: 22, +} as const; + +export const UNIT_OF_MEASURE_LABELS: Record = { + 1: 'Libra', + 2: 'Onza', + 3: 'Kilogramo', + 10: 'Unidad', + 11: 'Caja', + 12: 'Paquete', + 13: 'Saco', + 20: 'Litro', + 21: 'Galón', + 22: 'Botella', +} as const; + +export const UNIT_TYPE = { + UNIT: 1, + POUND: 2, + LITER: 3, + BOX: 4, +} as const; + +export const UNIT_TYPE_LABELS: Record = { + 1: 'Unidad', + 2: 'Libra', + 3: 'Litro', + 4: 'Caja', +} as const; + +export const DEFAULT_ITBIS_RATE = 0.18; +export const DEFAULT_CREDIT_LIMIT = 5000; +export const LOW_STOCK_THRESHOLD = 5; +export const DEFAULT_PAGE_SIZE = 20; +export const CATALOG_PAGE_SIZE = 24; + +export const QUICK_CASH_AMOUNTS = [500, 1000, 2000, 5000] as const; + +export const PRODUCT_COLORS = [ + 'bg-blue-700', + 'bg-violet-700', + 'bg-emerald-700', + 'bg-amber-700', + 'bg-rose-700', + 'bg-cyan-700', + 'bg-indigo-700', + 'bg-teal-700', +] as const; + +export const NOMINATIM_BASE_URL = 'https://nominatim.openstreetmap.org/search'; +export const OPENFREEMAP_STYLE_URL = 'https://tiles.openfreemap.org/styles/liberty'; +export const WHATSAPP_BASE_URL = 'https://wa.me'; +export const GOOGLE_MAPS_BASE_URL = 'https://www.google.com/maps/search/?api=1&query='; +export const WAZE_BASE_URL = 'https://waze.com/ul?ll='; +export const DR_LOCALE = 'es-DO'; +export const DR_CURRENCY_CODE = 'DOP'; +export const SANTO_DOMINGO_COORDS = [-69.9, 18.5] as const; + +export const ERROR_MESSAGES: Record = { + 'product.sale_price_below_cost': 'El precio de venta no puede ser menor al costo.', + 'product.category_required': 'Selecciona una categoría.', + 'product.name_required': 'El nombre del producto es obligatorio.', + 'product.invalid_price': 'El precio ingresado no es válido.', + 'category.not_found': 'La categoría seleccionada no existe.', + 'auth.token_missing': 'Token de autenticación no encontrado.', + 'fund.insufficient_balance': 'El fondo no tiene balance suficiente.', + 'fund.justification_required': 'Se requiere justificación para gastos mayores al balance.', +} as const; + +export const EXPENSE_CATEGORIES_LEGACY = [ + { value: 'Utilities', label: 'Servicios (Agua/Luz/Tel)' }, + { value: 'Maintenance', label: 'Mantenimiento' }, + { value: 'Supplies', label: 'Insumos y suministros' }, + { value: 'Hielo', label: 'Hielo' }, + { value: 'Personnel', label: 'Personal' }, + { value: 'Other', label: 'Otro' }, +] as const; + +export const ROLE_LABELS: Record = { + Owner: 'Dueño', + Admin: 'Administrador', + Seller: 'Vendedor', + Cashier: 'Cajero', + Delivery: 'Repartidor', +} as const; + +export const SHIFT_STATUS_LABELS: Record = { + Open: 'Abierto', + Closed: 'Cerrado', +} as const; + +export const API_PATHS = { + INVENTORY_PRODUCTS: '/api/v1/inventory/products', + INVENTORY_CATEGORIES: '/api/v1/inventory/categories', + INVENTORY_CATALOG: '/api/v1/inventory/catalog', + INVENTORY_LOW_STOCK: '/api/v1/inventory/products/low-stock', + INVENTORY_PRESENTATIONS: (productId: string) => `/api/v1/inventory/products/${productId}/presentations`, + INVENTORY_STOCK_ENTRIES: '/api/v1/inventory/stock-entries', + INVENTORY_CONTAINER_DRAW: (id: string) => `/api/v1/inventory/containers/${id}/draw`, + INVENTORY_CONTAINER_EMPTY: (id: string) => `/api/v1/inventory/containers/${id}/empty`, + INVENTORY_ACTIVE_CONTAINER: (presentationId: string) => `/api/v1/inventory/presentations/${presentationId}/active-container`, + INVENTORY_OPEN_CONTAINERS: (presentationId: string) => `/api/v1/inventory/presentations/${presentationId}/containers`, + INVENTORY_FUNDS: '/api/v1/inventory/funds', + INVENTORY_FUND: (id: string) => `/api/v1/inventory/funds/${id}`, + INVENTORY_FUND_DEPOSIT: (id: string) => `/api/v1/inventory/funds/${id}/deposit`, + INVENTORY_FUND_EXPENSE: (id: string) => `/api/v1/inventory/funds/${id}/expense`, + SALES: '/api/v1/sales', + SALES_SHIFTS: '/api/v1/sales/shifts', + SALES_SHIFTS_CURRENT: '/api/v1/sales/shifts/current', + SALES_SHIFTS_SUMMARY: '/api/v1/sales/shifts/current/summary', + CUSTOMERS: '/api/v1/customers', + CUSTOMER_STATEMENT: (id: string) => `/api/v1/customers/${id}/statement`, + CUSTOMER_PAYMENTS: (id: string) => `/api/v1/customers/${id}/payments`, + EXPENSES: '/api/v1/expenses', + DELIVERY_PENDING: '/api/v1/logistics/delivery/pending', + DELIVERY_ACCEPT: (id: string) => `/api/v1/logistics/delivery/${id}/accept`, + DELIVERY_COMPLETE: (id: string) => `/api/v1/logistics/delivery/${id}/complete`, + SETTINGS_PROFILE: '/api/v1/settings/profile', + REPORTS_SALES: '/api/v1/reports/sales', + REPORTS_INVENTORY_ALERTS: '/api/v1/reports/inventory-alerts', + REPORTS_CUSTOMERS: '/api/v1/reports/customers', + AUTH_LOGIN: '/auth/login', + AUTH_REGISTER: '/auth/register', + AUTH_VERIFY_EMAIL: '/auth/verify-email', + AUTH_EMPLOYEES: '/auth/employees', +} as const; diff --git a/frontend/web-admin/src/app/core/interceptors/auth.interceptor.ts b/frontend/web-admin/src/app/core/interceptors/auth.interceptor.ts index 49ac00f..c21977e 100644 --- a/frontend/web-admin/src/app/core/interceptors/auth.interceptor.ts +++ b/frontend/web-admin/src/app/core/interceptors/auth.interceptor.ts @@ -1,29 +1,30 @@ -import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http'; -import { inject } from '@angular/core'; -import { environment } from '../../../environments/environment'; -import { AuthService } from '../services/auth.service'; -import { catchError, throwError } from 'rxjs'; - -export const authInterceptor: HttpInterceptorFn = (req, next) => { - const authService = inject(AuthService); - const token = localStorage.getItem('tc_token'); - const isGatewayUrl = req.url.startsWith(environment.gatewayUrl); - - if (token && isGatewayUrl) { - req = req.clone({ - setHeaders: { - Authorization: `Bearer ${token}` - } - }); - } - - return next(req).pipe( - catchError((error: HttpErrorResponse) => { - const isAuthEndpoint = req.url.includes('/auth/login') || req.url.includes('/auth/register'); - if (error.status === 401 && !isAuthEndpoint) { - authService.logout(); - } - return throwError(() => error); - }) - ); -}; +import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { environment } from '../../../environments/environment'; +import { AuthService } from '../services/auth.service'; +import { LS_KEYS } from '../constants'; +import { catchError, throwError } from 'rxjs'; + +export const authInterceptor: HttpInterceptorFn = (req, next) => { + const authService = inject(AuthService); + const token = localStorage.getItem(LS_KEYS.TOKEN); + const isGatewayUrl = req.url.startsWith(environment.gatewayUrl); + + if (token && isGatewayUrl) { + req = req.clone({ + setHeaders: { + Authorization: `Bearer ${token}` + } + }); + } + + return next(req).pipe( + catchError((error: HttpErrorResponse) => { + const isAuthEndpoint = req.url.includes('/auth/login') || req.url.includes('/auth/register'); + if (error.status === 401 && !isAuthEndpoint) { + authService.logout(); + } + return throwError(() => error); + }) + ); +}; diff --git a/frontend/web-admin/src/app/core/models/fund.models.ts b/frontend/web-admin/src/app/core/models/fund.models.ts new file mode 100644 index 0000000..0cc6000 --- /dev/null +++ b/frontend/web-admin/src/app/core/models/fund.models.ts @@ -0,0 +1,53 @@ +export interface MonetaryFundDto { + id: string; + tenantId: string; + name: string; + currentBalance: number; + createdAt: string; +} + +export interface FundTransactionDto { + id: string; + fundId: string; + type: number; + typeName: string; + amount: number; + category: number | null; + categoryName: string | null; + description: string; + justificationNote: string | null; + referenceId: string | null; + balanceAfter: number; + occurredAt: string; +} + +export interface CreateMonetaryFundRequest { + name: string; + initialDeposit: number; +} + +export interface RecordFundDepositRequest { + amount: number; + description: string; +} + +export interface RecordFundExpenseRequest { + amount: number; + category: number; + description: string; + justificationNote?: string | null; + referenceId?: string | null; +} + +export interface FundBalanceResponse { + fund: MonetaryFundDto; + recentTransactions: FundTransactionDto[]; +} + +export interface PagedFundTransactionsResponse { + items: FundTransactionDto[]; + pageNumber: number; + pageSize: number; + totalCount: number; + totalPages: number; +} diff --git a/frontend/web-admin/src/app/core/models/inventory.models.ts b/frontend/web-admin/src/app/core/models/inventory.models.ts new file mode 100644 index 0000000..9080de5 --- /dev/null +++ b/frontend/web-admin/src/app/core/models/inventory.models.ts @@ -0,0 +1,158 @@ +export interface ProductDto { + productId: string; + name: string; + categoryId: string; + categoryName: string; + itbisRate: number; + isActive: boolean; + updatedAt: string; + presentations: ProductPresentationDto[]; +} + +export interface ProductPresentationDto { + id: string; + productId: string; + displayName: string; + presentationType: number; + presentationTypeName: string; + sellMode: number; + sellModeName: string; + brand: string | null; + nominalCapacity: number | null; + measureUnit: number; + measureUnitName: string; + salePrice: number; + costPrice: number; + isActive: boolean; + stockQuantity: number; + openContainersCount: number; + packagedStockQuantity: number; +} + +export interface StockContainerDto { + id: string; + presentationId: string; + containerCode: string; + nominalCapacity: number; + actualCapacity: number | null; + currentRemaining: number; + status: number; + statusName: string; + isActiveSource: boolean; + notes: string | null; + purchasedAt: string; + openedAt: string | null; + emptiedAt: string | null; +} + +export interface PackagedStockDto { + id: string; + presentationId: string; + quantity: number; + lastUpdatedAt: string; +} + +export interface StockEntryDto { + id: string; + purchasedAt: string; + totalCost: number; + supplierName: string | null; + notes: string | null; + fundTransactionId: string | null; + lines: StockEntryLineDto[]; +} + +export interface StockEntryLineDto { + id: string; + stockEntryId: string; + presentationId: string; + presentationDisplayName: string; + containerCount: number; + unitsPerContainer: number; + nominalSizePerUnit: number; + costPerUnit: number; + lineTotal: number; +} + +export interface PagedProductsResponse { + items: ProductDto[]; + pageNumber: number; + pageSize: number; + totalCount: number; + totalPages: number; +} + +export interface CreateProductRequest { + name: string; + categoryId: string; + itbisRate: number; +} + +export interface AddProductPresentationRequest { + displayName: string; + presentationType: number; + sellMode: number; + brand?: string | null; + nominalCapacity?: number | null; + measureUnit: number; + salePrice: number; + costPrice: number; +} + +export interface UpdatePresentationPriceRequest { + salePrice: number; + costPrice: number; +} + +export interface StockEntryLineRequest { + presentationId: string; + containerCount: number; + unitsPerContainer: number; + nominalSizePerUnit: number; + costPerUnit: number; +} + +export interface ConfirmStockEntryRequest { + purchasedAt?: string; + supplierName?: string | null; + notes?: string | null; + fundId?: string | null; + fundExpenseJustification?: string | null; + lines: StockEntryLineRequest[]; +} + +export interface OpenContainerRequest { + actualCapacity?: number | null; +} + +export interface DrawFromContainerRequest { + amount: number; + allowOverDraw?: boolean; +} + +export interface SetActiveContainerRequest { + containerId: string; +} + +export interface CategoryDto { + id: string; + name: string; +} + +export interface LowStockPresentationDto { + presentationId: string; + productName: string; + presentationDisplayName: string; + stockQuantity: number; + threshold: number; +} + +export interface OpenContainerSummaryDto { + id: string; + containerCode: string; + currentRemaining: number; + nominalCapacity: number; + statusName: string; + isActiveSource: boolean; + openedAt: string | null; +} diff --git a/frontend/web-admin/src/app/core/services/auth.service.ts b/frontend/web-admin/src/app/core/services/auth.service.ts index acf91d6..5e19d93 100644 --- a/frontend/web-admin/src/app/core/services/auth.service.ts +++ b/frontend/web-admin/src/app/core/services/auth.service.ts @@ -1,98 +1,98 @@ -import { Injectable, signal, inject, computed } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Router } from '@angular/router'; -import { Observable, tap } from 'rxjs'; -import { environment } from '../../../environments/environment'; -import { AuthResponse, AuthUser, LoginRequest, RegisterRequest } from '../models/auth.models'; - -@Injectable({ - providedIn: 'root' -}) -export class AuthService { - private http = inject(HttpClient); - private router = inject(Router); - private baseUrl = `${environment.gatewayUrl}/gateway`; - - // State - currentUser = signal(this.getUserFromStorage()); - token = signal(localStorage.getItem('tc_token')); - isLicenseExpired = computed(() => - this.currentUser()?.subscriptionStatus === 'expired' - ); - - login(credentials: LoginRequest): Observable { - return this.http.post(`${this.baseUrl}/auth/login`, credentials).pipe( - tap(res => this.setSession(res)) - ); - } - - register(data: RegisterRequest): Observable { - return this.http.post(`${this.baseUrl}/auth/register`, data).pipe( - tap(res => { - if (res.token || res.accessToken) { - this.setSession(res); - } - }) - ); - } - - verifyEmail(email: string, code: string): Observable { - return this.http.post(`${this.baseUrl}/auth/verify-email`, { email, code }).pipe( - tap(res => this.setSession(res)) - ); - } - - logout(): void { - localStorage.removeItem('tc_token'); - localStorage.removeItem('tc_user'); - localStorage.removeItem('tc_tenant'); - this.currentUser.set(null); - this.token.set(null); - this.router.navigate(['/auth/login']); - } - - isAuthenticated(): boolean { - const token = this.token(); - if (!token) return false; - - try { - const payload = JSON.parse(atob(token.split('.')[1])); - const isExpired = Date.now() >= payload.exp * 1000; - return !isExpired; - } catch { - return false; - } - } - - private setSession(authRes: AuthResponse): void { - const token = authRes.token ?? authRes.accessToken; - const tenantId = authRes.tenantId ?? authRes.user?.tenantId ?? null; - - if (!token) { - throw new Error('AUTH_TOKEN_MISSING'); - } - - localStorage.setItem('tc_token', token); - if (authRes.user) { - localStorage.setItem('tc_user', JSON.stringify(authRes.user)); - this.currentUser.set(authRes.user); - } else { - localStorage.removeItem('tc_user'); - this.currentUser.set(null); - } - - if (tenantId) { - localStorage.setItem('tc_tenant', tenantId); - } else { - localStorage.removeItem('tc_tenant'); - } - - this.token.set(token); - } - - private getUserFromStorage(): AuthUser | null { - const userStr = localStorage.getItem('tc_user'); - if (!userStr) return null; - try { return JSON.parse(userStr); } catch { return null; } - } -} +import { Injectable, signal, inject, computed } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Router } from '@angular/router'; +import { Observable, tap } from 'rxjs'; +import { environment } from '../../../environments/environment'; +import { AuthResponse, AuthUser, LoginRequest, RegisterRequest } from '../models/auth.models'; +import { LS_KEYS, API_PATHS, ERROR_MESSAGES } from '../constants'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + private http = inject(HttpClient); + private router = inject(Router); + private baseUrl = `${environment.gatewayUrl}/gateway`; + + currentUser = signal(this.getUserFromStorage()); + token = signal(localStorage.getItem(LS_KEYS.TOKEN)); + isLicenseExpired = computed(() => + this.currentUser()?.subscriptionStatus === 'expired' + ); + + login(credentials: LoginRequest): Observable { + return this.http.post(`${this.baseUrl}${API_PATHS.AUTH_LOGIN}`, credentials).pipe( + tap(res => this.setSession(res)) + ); + } + + register(data: RegisterRequest): Observable { + return this.http.post(`${this.baseUrl}${API_PATHS.AUTH_REGISTER}`, data).pipe( + tap(res => { + if (res.token || res.accessToken) { + this.setSession(res); + } + }) + ); + } + + verifyEmail(email: string, code: string): Observable { + return this.http.post(`${this.baseUrl}${API_PATHS.AUTH_VERIFY_EMAIL}`, { email, code }).pipe( + tap(res => this.setSession(res)) + ); + } + + logout(): void { + localStorage.removeItem(LS_KEYS.TOKEN); + localStorage.removeItem(LS_KEYS.USER); + localStorage.removeItem(LS_KEYS.TENANT); + this.currentUser.set(null); + this.token.set(null); + this.router.navigate(['/auth/login']); + } + + isAuthenticated(): boolean { + const token = this.token(); + if (!token) return false; + + try { + const payload = JSON.parse(atob(token.split('.')[1])); + const isExpired = Date.now() >= payload.exp * 1000; + return !isExpired; + } catch { + return false; + } + } + + private setSession(authRes: AuthResponse): void { + const token = authRes.token ?? authRes.accessToken; + const tenantId = authRes.tenantId ?? authRes.user?.tenantId ?? null; + + if (!token) { + throw new Error(ERROR_MESSAGES['auth.token_missing']); + } + + localStorage.setItem(LS_KEYS.TOKEN, token); + if (authRes.user) { + localStorage.setItem(LS_KEYS.USER, JSON.stringify(authRes.user)); + this.currentUser.set(authRes.user); + } else { + localStorage.removeItem(LS_KEYS.USER); + this.currentUser.set(null); + } + + if (tenantId) { + localStorage.setItem(LS_KEYS.TENANT, tenantId); + } else { + localStorage.removeItem(LS_KEYS.TENANT); + } + + this.token.set(token); + } + + private getUserFromStorage(): AuthUser | null { + const userStr = localStorage.getItem(LS_KEYS.USER); + if (!userStr) return null; + try { return JSON.parse(userStr); } catch { return null; } + } +} diff --git a/frontend/web-admin/src/app/core/services/customer.service.ts b/frontend/web-admin/src/app/core/services/customer.service.ts index 1241000..cdeabb3 100644 --- a/frontend/web-admin/src/app/core/services/customer.service.ts +++ b/frontend/web-admin/src/app/core/services/customer.service.ts @@ -1,72 +1,73 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface CustomerSummary { - customerId: string; - fullName: string; - phone: string; - balance: number; - creditLimit: number; - isActive: boolean; - province?: string | null; - sector?: string | null; - street?: string | null; - houseNumber?: string | null; - reference?: string | null; - latitude?: number | null; - longitude?: number | null; -} - -export interface CustomerStatementEntry { - transactionId: string; - date: string; - type: string; - amount: number; - concept: string; -} - -export interface CreateCustomerAddressRequest { - province: string; - sector: string; - street: string; - reference: string; - houseNumber?: string; - latitude?: number; - longitude?: number; -} - -export interface CreateCustomerRequest { - fullName: string; - documentId: string; - phone: string | null; - address?: CreateCustomerAddressRequest | null; - creditLimit: number | null; -} - -export interface RegisterPaymentRequest { - amount: number; - paymentMethodId: number; - concept: string; -} - -@Injectable({ providedIn: 'root' }) -export class CustomerService { - private gateway = inject(GatewayService); - - getCustomers(): Observable { - return this.gateway.get('/api/v1/customers'); - } - - createCustomer(req: CreateCustomerRequest): Observable<{ customerId: string }> { - return this.gateway.post('/api/v1/customers', req); - } - - registerPayment(customerId: string, req: RegisterPaymentRequest): Observable { - return this.gateway.post(`/api/v1/customers/${customerId}/payments`, req); - } - - getStatement(customerId: string): Observable { - return this.gateway.get(`/api/v1/customers/${customerId}/statement`); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS } from '../constants'; + +export interface CustomerSummary { + customerId: string; + fullName: string; + phone: string; + balance: number; + creditLimit: number; + isActive: boolean; + province?: string | null; + sector?: string | null; + street?: string | null; + houseNumber?: string | null; + reference?: string | null; + latitude?: number | null; + longitude?: number | null; +} + +export interface CustomerStatementEntry { + transactionId: string; + date: string; + type: string; + amount: number; + concept: string; +} + +export interface CreateCustomerAddressRequest { + province: string; + sector: string; + street: string; + reference: string; + houseNumber?: string; + latitude?: number; + longitude?: number; +} + +export interface CreateCustomerRequest { + fullName: string; + documentId: string; + phone: string | null; + address?: CreateCustomerAddressRequest | null; + creditLimit: number | null; +} + +export interface RegisterPaymentRequest { + amount: number; + paymentMethodId: number; + concept: string; +} + +@Injectable({ providedIn: 'root' }) +export class CustomerService { + private gateway = inject(GatewayService); + + getCustomers(): Observable { + return this.gateway.get(API_PATHS.CUSTOMERS); + } + + createCustomer(req: CreateCustomerRequest): Observable<{ customerId: string }> { + return this.gateway.post(API_PATHS.CUSTOMERS, req); + } + + registerPayment(customerId: string, req: RegisterPaymentRequest): Observable { + return this.gateway.post(API_PATHS.CUSTOMER_PAYMENTS(customerId), req); + } + + getStatement(customerId: string): Observable { + return this.gateway.get(API_PATHS.CUSTOMER_STATEMENT(customerId)); + } +} diff --git a/frontend/web-admin/src/app/core/services/delivery.service.ts b/frontend/web-admin/src/app/core/services/delivery.service.ts index b8f52c6..2e02e3b 100644 --- a/frontend/web-admin/src/app/core/services/delivery.service.ts +++ b/frontend/web-admin/src/app/core/services/delivery.service.ts @@ -1,49 +1,50 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface DeliveryOrderDto { - id: string; - saleId: string; - receiptNumber: string; - totalAmount: number; - customerName: string; - customerPhone: string; - province: string; - sector: string; - street: string; - houseNumber?: string | null; - reference: string; - latitude?: number | null; - longitude?: number | null; - status: string; - confirmationCode: string; -} - -@Injectable({ providedIn: 'root' }) -export class DeliveryService { - private gateway = inject(GatewayService); - - getPendingOrders(): Observable { - return this.gateway.get('/api/v1/logistics/delivery/pending'); - } - - acceptOrder(id: string): Observable<{ status: string }> { - return this.gateway.post<{ status: string }>(`/api/v1/logistics/delivery/${id}/accept`, {}); - } - - completeOrder( - id: string, - totalAmount: number, - confirmationCode: string, - driverLatitude?: number | null, - driverLongitude?: number | null - ): Observable<{ status: string }> { - return this.gateway.post<{ status: string }>(`/api/v1/logistics/delivery/${id}/complete`, { - payments: [{ paymentMethodId: 1, amount: totalAmount, reference: null, customerId: null }], - confirmationCode, - driverLatitude: driverLatitude ?? null, - driverLongitude: driverLongitude ?? null - }); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS, PAYMENT_METHOD } from '../constants'; + +export interface DeliveryOrderDto { + id: string; + saleId: string; + receiptNumber: string; + totalAmount: number; + customerName: string; + customerPhone: string; + province: string; + sector: string; + street: string; + houseNumber?: string | null; + reference: string; + latitude?: number | null; + longitude?: number | null; + status: string; + confirmationCode: string; +} + +@Injectable({ providedIn: 'root' }) +export class DeliveryService { + private gateway = inject(GatewayService); + + getPendingOrders(): Observable { + return this.gateway.get(API_PATHS.DELIVERY_PENDING); + } + + acceptOrder(id: string): Observable<{ status: string }> { + return this.gateway.post<{ status: string }>(API_PATHS.DELIVERY_ACCEPT(id), {}); + } + + completeOrder( + id: string, + totalAmount: number, + confirmationCode: string, + driverLatitude?: number | null, + driverLongitude?: number | null + ): Observable<{ status: string }> { + return this.gateway.post<{ status: string }>(API_PATHS.DELIVERY_COMPLETE(id), { + payments: [{ paymentMethodId: PAYMENT_METHOD.CASH, amount: totalAmount, reference: null, customerId: null }], + confirmationCode, + driverLatitude: driverLatitude ?? null, + driverLongitude: driverLongitude ?? null + }); + } +} diff --git a/frontend/web-admin/src/app/core/services/employee.service.ts b/frontend/web-admin/src/app/core/services/employee.service.ts index a10b6a5..378b660 100644 --- a/frontend/web-admin/src/app/core/services/employee.service.ts +++ b/frontend/web-admin/src/app/core/services/employee.service.ts @@ -1,51 +1,50 @@ -import { Injectable, inject } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from '../../../environments/environment'; - -export interface EmployeeDto { - _id: string; - email: string; - firstName: string | null; - lastName: string | null; - role: string; - isActive: boolean; - createdAt: string; - tenantId: string; -} - -export interface CreateEmployeeDto { - email: string; - password: string; - firstName?: string; - lastName?: string; - role: string; -} - -export interface UpdateEmployeeDto { - firstName?: string; - lastName?: string; - role?: string; -} - -@Injectable({ providedIn: 'root' }) -export class EmployeeService { - private http = inject(HttpClient); - private base = `${environment.gatewayUrl}/gateway/auth/employees`; - - list(): Observable { - return this.http.get(this.base); - } - - create(data: CreateEmployeeDto): Observable { - return this.http.post(this.base, data); - } - - update(id: string, data: UpdateEmployeeDto): Observable { - return this.http.put(`${this.base}/${id}`, data); - } - - toggle(id: string, active: boolean): Observable { - return this.http.patch(`${this.base}/${id}`, { active }); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS } from '../constants'; + +export interface EmployeeDto { + _id: string; + email: string; + firstName: string | null; + lastName: string | null; + role: string; + isActive: boolean; + createdAt: string; + tenantId: string; +} + +export interface CreateEmployeeDto { + email: string; + password: string; + firstName?: string; + lastName?: string; + role: string; +} + +export interface UpdateEmployeeDto { + firstName?: string; + lastName?: string; + role?: string; +} + +@Injectable({ providedIn: 'root' }) +export class EmployeeService { + private gateway = inject(GatewayService); + + list(): Observable { + return this.gateway.get(API_PATHS.AUTH_EMPLOYEES); + } + + create(data: CreateEmployeeDto): Observable { + return this.gateway.post(API_PATHS.AUTH_EMPLOYEES, data); + } + + update(id: string, data: UpdateEmployeeDto): Observable { + return this.gateway.put(`${API_PATHS.AUTH_EMPLOYEES}/${id}`, data); + } + + toggle(id: string, active: boolean): Observable { + return this.gateway.patch(`${API_PATHS.AUTH_EMPLOYEES}/${id}`, { active }); + } +} diff --git a/frontend/web-admin/src/app/core/services/expense.service.ts b/frontend/web-admin/src/app/core/services/expense.service.ts index 4be3a81..0ac11e5 100644 --- a/frontend/web-admin/src/app/core/services/expense.service.ts +++ b/frontend/web-admin/src/app/core/services/expense.service.ts @@ -1,30 +1,31 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface ExpenseSummary { - id: string; - amount: number; - category: string; - description: string; - date: string; -} - -export interface RegisterExpenseRequest { - amount: number; - category: string; - description: string; -} - -@Injectable({ providedIn: 'root' }) -export class ExpenseService { - private gw = inject(GatewayService); - - getExpenses(page = 1, pageSize = 50): Observable { - return this.gw.get('/api/v1/expenses', { page, pageSize }); - } - - registerExpense(req: RegisterExpenseRequest): Observable { - return this.gw.post('/api/v1/expenses', req); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS } from '../constants'; + +export interface ExpenseSummary { + id: string; + amount: number; + category: string; + description: string; + date: string; +} + +export interface RegisterExpenseRequest { + amount: number; + category: string; + description: string; +} + +@Injectable({ providedIn: 'root' }) +export class ExpenseService { + private gw = inject(GatewayService); + + getExpenses(page = 1, pageSize = 50): Observable { + return this.gw.get(API_PATHS.EXPENSES, { page, pageSize }); + } + + registerExpense(req: RegisterExpenseRequest): Observable { + return this.gw.post(API_PATHS.EXPENSES, req); + } +} diff --git a/frontend/web-admin/src/app/core/services/gateway.service.ts b/frontend/web-admin/src/app/core/services/gateway.service.ts index 5a6e08f..28db1c5 100644 --- a/frontend/web-admin/src/app/core/services/gateway.service.ts +++ b/frontend/web-admin/src/app/core/services/gateway.service.ts @@ -27,6 +27,10 @@ export class GatewayService { return this.http.delete(`${this.base}${this.cleanPath(path)}`); } + patch(path: string, body: any): Observable { + return this.http.patch(`${this.base}${this.cleanPath(path)}`, body); + } + private cleanPath(path: string): string { return path.startsWith('/') ? path : `/${path}`; } diff --git a/frontend/web-admin/src/app/core/services/inventory.service.ts b/frontend/web-admin/src/app/core/services/inventory.service.ts index f0fc5c0..b643101 100644 --- a/frontend/web-admin/src/app/core/services/inventory.service.ts +++ b/frontend/web-admin/src/app/core/services/inventory.service.ts @@ -1,106 +1,129 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface ProductDto { - productId: string; - name: string; - categoryId: string; - categoryName: string; - costPrice: number; - salePrice: number; - itbisRate: number; - unitTypeId: number; - unitTypeName: string; - stockQuantity: number; - isActive: boolean; - updatedAt: string; -} - -export interface PagedProductsResponse { - items: ProductDto[]; - pageNumber: number; - pageSize: number; - totalCount: number; - totalPages: number; -} - -export interface CreateProductRequest { - name: string; - categoryId: string; - costPrice: number; - salePrice: number; - itbisRate: number; - unitType: number; -} - -export interface UpdatePriceRequest { - newCostPrice: number; - newSalePrice: number; -} - -export interface AdjustStockRequest { - delta: number; - reason: string; -} - -export interface CategoryDto { - id: string; - name: string; -} - -@Injectable({ providedIn: 'root' }) -export class InventoryService { - private gateway = inject(GatewayService); - - getProducts(page = 1, pageSize = 20, nameFilter?: string, categoryId?: string): Observable { - const params: any = { page, pageSize }; - if (nameFilter) params['nameFilter'] = nameFilter; - if (categoryId) params['categoryId'] = categoryId; - return this.gateway.get('/api/v1/inventory/products', params); - } - - getProductById(id: string): Observable { - return this.gateway.get(`/api/v1/inventory/products/${id}`); - } - - createProduct(cmd: CreateProductRequest): Observable<{ productId: string }> { - return this.gateway.post('/api/v1/inventory/products', cmd); - } - - updatePrice(id: string, req: UpdatePriceRequest): Observable { - return this.gateway.put(`/api/v1/inventory/products/${id}/price`, req); - } - - adjustStock(id: string, req: AdjustStockRequest): Observable<{ newStockQuantity: number }> { - return this.gateway.post(`/api/v1/inventory/products/${id}/stock/adjust`, req); - } - - deactivateProduct(id: string): Observable { - return this.gateway.delete(`/api/v1/inventory/products/${id}`); - } - - getCatalog(): Observable { - return this.gateway.get('/api/v1/inventory/catalog'); - } - - getLowStock(threshold = 5): Observable<{ count: number; items: { productId: string; name: string; stockQuantity: number }[] }> { - return this.gateway.get('/api/v1/inventory/products/low-stock', { threshold }); - } - - getCategories(): Observable { - return this.gateway.get('/api/v1/inventory/categories'); - } - - createCategory(name: string): Observable<{ id: string }> { - return this.gateway.post<{ id: string }>('/api/v1/inventory/categories', { name }); - } - - seedDefaultCategories(): Observable<{ created: number }> { - return this.gateway.post<{ created: number }>('/api/v1/inventory/categories/seed-defaults', {}); - } - - deactivateCategory(id: string): Observable { - return this.gateway.delete(`/api/v1/inventory/categories/${id}`); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { + ProductDto, + PagedProductsResponse, + CreateProductRequest, + UpdatePresentationPriceRequest, + StockEntryLineRequest, + ConfirmStockEntryRequest, + OpenContainerRequest, + DrawFromContainerRequest, + SetActiveContainerRequest, + StockContainerDto, + StockEntryDto, + ProductPresentationDto, + LowStockPresentationDto, + OpenContainerSummaryDto, + CategoryDto, +} from '../models/inventory.models'; +export type { CategoryDto, ProductPresentationDto, StockContainerDto, StockEntryDto, ProductDto, PagedProductsResponse, CreateProductRequest, UpdatePresentationPriceRequest, StockEntryLineRequest, ConfirmStockEntryRequest, OpenContainerRequest, DrawFromContainerRequest, SetActiveContainerRequest, LowStockPresentationDto, OpenContainerSummaryDto } from '../models/inventory.models'; +import { API_PATHS, LOW_STOCK_THRESHOLD } from '../constants'; + +@Injectable({ providedIn: 'root' }) +export class InventoryService { + private gateway = inject(GatewayService); + + getProducts(page = 1, pageSize = 20, nameFilter?: string, categoryId?: string): Observable { + const params: any = { page, pageSize }; + if (nameFilter) params['nameFilter'] = nameFilter; + if (categoryId) params['categoryId'] = categoryId; + return this.gateway.get(API_PATHS.INVENTORY_PRODUCTS, params); + } + + getProductById(id: string): Observable { + return this.gateway.get(`${API_PATHS.INVENTORY_PRODUCTS}/${id}`); + } + + createProduct(cmd: CreateProductRequest): Observable<{ productId: string }> { + return this.gateway.post(API_PATHS.INVENTORY_PRODUCTS, cmd); + } + + updatePresentationPrice(presentationId: string, req: UpdatePresentationPriceRequest): Observable { + return this.gateway.put(`/api/v1/inventory/presentations/${presentationId}/price`, req); + } + + deactivateProduct(id: string): Observable { + return this.gateway.delete(`${API_PATHS.INVENTORY_PRODUCTS}/${id}`); + } + + getCatalog(): Observable { + return this.gateway.get(API_PATHS.INVENTORY_CATALOG); + } + + getLowStockPresentations(threshold = LOW_STOCK_THRESHOLD): Observable<{ count: number; items: LowStockPresentationDto[] }> { + return this.gateway.get(API_PATHS.INVENTORY_LOW_STOCK, { threshold }); + } + + getCategories(): Observable { + return this.gateway.get(API_PATHS.INVENTORY_CATEGORIES); + } + + createCategory(name: string): Observable<{ id: string }> { + return this.gateway.post<{ id: string }>(API_PATHS.INVENTORY_CATEGORIES, { name }); + } + + seedDefaultCategories(): Observable<{ created: number }> { + return this.gateway.post<{ created: number }>(`${API_PATHS.INVENTORY_CATEGORIES}/seed-defaults`, {}); + } + + deactivateCategory(id: string): Observable { + return this.gateway.delete(`${API_PATHS.INVENTORY_CATEGORIES}/${id}`); + } + + addPresentation(productId: string, cmd: { + displayName: string; + presentationType: number; + sellMode: number; + brand?: string | null; + nominalCapacity?: number | null; + measureUnit: number; + salePrice: number; + costPrice: number; + }): Observable<{ id: string }> { + return this.gateway.post(API_PATHS.INVENTORY_PRESENTATIONS(productId), cmd); + } + + getPresentations(productId: string): Observable { + return this.gateway.get(API_PATHS.INVENTORY_PRESENTATIONS(productId)); + } + + deactivatePresentation(presentationId: string): Observable { + return this.gateway.delete(`/api/v1/inventory/presentations/${presentationId}`); + } + + confirmStockEntry(cmd: ConfirmStockEntryRequest): Observable<{ stockEntryId: string }> { + return this.gateway.post(API_PATHS.INVENTORY_STOCK_ENTRIES, cmd); + } + + getStockEntries(page = 1, pageSize = 20): Observable<{ items: StockEntryDto[]; totalCount: number; totalPages: number }> { + return this.gateway.get(API_PATHS.INVENTORY_STOCK_ENTRIES, { page, pageSize }); + } + + openContainer(containerId: string, cmd: OpenContainerRequest): Observable { + return this.gateway.post(`/api/v1/inventory/containers/${containerId}/open`, cmd); + } + + drawFromContainer(containerId: string, cmd: DrawFromContainerRequest): Observable<{ remaining: number }> { + return this.gateway.post(API_PATHS.INVENTORY_CONTAINER_DRAW(containerId), cmd); + } + + markContainerEmpty(containerId: string): Observable { + return this.gateway.post(API_PATHS.INVENTORY_CONTAINER_EMPTY(containerId), {}); + } + + setActiveContainer(presentationId: string, cmd: SetActiveContainerRequest): Observable { + return this.gateway.put(API_PATHS.INVENTORY_ACTIVE_CONTAINER(presentationId), cmd); + } + + getOpenContainers(presentationId: string): Observable { + return this.gateway.get(API_PATHS.INVENTORY_OPEN_CONTAINERS(presentationId)); + } + + getContainersByPresentation(presentationId: string, status?: string): Observable { + const params: any = {}; + if (status) params['status'] = status; + return this.gateway.get(`/api/v1/inventory/presentations/${presentationId}/containers`, params); + } +} diff --git a/frontend/web-admin/src/app/core/services/monetary-fund.service.ts b/frontend/web-admin/src/app/core/services/monetary-fund.service.ts new file mode 100644 index 0000000..929104c --- /dev/null +++ b/frontend/web-admin/src/app/core/services/monetary-fund.service.ts @@ -0,0 +1,43 @@ +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { + MonetaryFundDto, + FundTransactionDto, + CreateMonetaryFundRequest, + RecordFundDepositRequest, + RecordFundExpenseRequest, + FundBalanceResponse, + PagedFundTransactionsResponse, +} from '../models/fund.models'; +export type { MonetaryFundDto, FundTransactionDto, FundBalanceResponse } from '../models/fund.models'; +import { API_PATHS } from '../constants'; + +@Injectable({ providedIn: 'root' }) +export class MonetaryFundService { + private gateway = inject(GatewayService); + + getFunds(): Observable { + return this.gateway.get(API_PATHS.INVENTORY_FUNDS); + } + + getFund(id: string): Observable { + return this.gateway.get(API_PATHS.INVENTORY_FUND(id)); + } + + createFund(cmd: CreateMonetaryFundRequest): Observable<{ id: string }> { + return this.gateway.post(API_PATHS.INVENTORY_FUNDS, cmd); + } + + recordDeposit(fundId: string, cmd: RecordFundDepositRequest): Observable<{ transactionId: string }> { + return this.gateway.post(API_PATHS.INVENTORY_FUND_DEPOSIT(fundId), cmd); + } + + recordExpense(fundId: string, cmd: RecordFundExpenseRequest): Observable<{ transactionId: string }> { + return this.gateway.post(API_PATHS.INVENTORY_FUND_EXPENSE(fundId), cmd); + } + + getTransactions(fundId: string, page = 1, pageSize = 20): Observable { + return this.gateway.get(`${API_PATHS.INVENTORY_FUND(fundId)}/transactions`, { page, pageSize }); + } +} diff --git a/frontend/web-admin/src/app/core/services/reports.service.ts b/frontend/web-admin/src/app/core/services/reports.service.ts index 952a645..6889490 100644 --- a/frontend/web-admin/src/app/core/services/reports.service.ts +++ b/frontend/web-admin/src/app/core/services/reports.service.ts @@ -1,6 +1,7 @@ import { Injectable, inject } from '@angular/core'; import { Observable } from 'rxjs'; import { GatewayService } from './gateway.service'; +import { AuthService } from './auth.service'; export interface TopProduct { product_name: string; @@ -44,9 +45,10 @@ export interface CustomerReport { @Injectable({ providedIn: 'root' }) export class ReportsService { private gateway = inject(GatewayService); + private auth = inject(AuthService); private tenantId(): string { - return localStorage.getItem('tc_tenant') ?? ''; + return this.auth.currentUser()?.tenantId ?? ''; } getSalesReport(from?: string, to?: string): Observable { diff --git a/frontend/web-admin/src/app/core/services/sale.service.ts b/frontend/web-admin/src/app/core/services/sale.service.ts index 89c0b61..239522b 100644 --- a/frontend/web-admin/src/app/core/services/sale.service.ts +++ b/frontend/web-admin/src/app/core/services/sale.service.ts @@ -1,154 +1,154 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface SaleSummary { - saleId: string; - receiptNumber: string; - statusId: number; - total: number; - totalPaid: number; - createdAt: string; - itemCount: number; -} - -export interface PagedSalesResponse { - items: SaleSummary[]; - page: number; - pageSize: number; - totalCount: number; - totalPages: number; - totalRevenue: number; -} - -export interface CreateSaleItemRequest { - productId: string; - quantity: number; -} - -export interface CreateSalePaymentRequest { - paymentMethodId: number; - amount: number; - reference?: string; - customerId?: string; -} - -export interface DeliveryAddressRequest { - province: string; - sector: string; - street: string; - reference: string; - houseNumber?: string; - latitude?: number; - longitude?: number; -} - -export interface CreateSaleRequest { - items: CreateSaleItemRequest[]; - payments: CreateSalePaymentRequest[]; - notes?: string | null; - buyerRnc?: string | null; - deliveryAddress?: DeliveryAddressRequest | null; -} - -export interface CreateSaleLineResult { - productId: string; - productName: string; - quantity: number; - unitPrice: number; - lineItbis: number; - lineTotal: number; -} - -export interface CreateSaleResult { - saleId: string; - receiptNumber: string; - ncfNumber: string | null; - subtotal: number; - totalItbis: number; - total: number; - totalPaid: number; - changeDue: number; - items: CreateSaleLineResult[]; - deliveryOrderId?: string | null; - confirmationCode?: string | null; -} - -export interface ShiftDto { - shiftId: string; - tenantId: string; - terminalId: string; - cashierName: string; - status: string; - openingCashAmount: number; - closingCashAmount: number | null; - openedAt: string; - closedAt: string | null; - expectedCashAmount: number | null; - actualCashAmount: number | null; - cashDifference: number | null; - notes: string | null; - totalSalesCount: number; - totalSalesAmount: number; -} - -export interface ShiftSummaryDto { - shiftId: string; - openedAt: string; - openingCashAmount: number; - totalCashSales: number; - totalAccountPayments: number; - totalExpenses: number; - expectedCashAmount: number; -} - -export interface OpenShiftRequest { - openingCashAmount: number; - cashierName: string; -} - -export interface CloseShiftRequest { - actualCashAmount: number; - notes?: string; -} - -@Injectable({ - providedIn: 'root' -}) -export class SaleService { - private gateway = inject(GatewayService); - - // Sales - getSales(page = 1, pageSize = 10): Observable { - return this.gateway.get('/api/v1/sales', { page, pageSize }); - } - - createSale(cmd: CreateSaleRequest): Observable { - return this.gateway.post('/api/v1/sales', cmd); - } - - voidSale(id: string, reason: string): Observable { - return this.gateway.post(`/api/v1/sales/${id}/void`, { voidReason: reason }); - } - - // Shifts - getCurrentShift(): Observable { - return this.gateway.get('/api/v1/sales/shifts/current'); - } - - openShift(cmd: OpenShiftRequest): Observable<{ shiftId: string }> { - return this.gateway.post('/api/v1/sales/shifts/open', cmd); - } - - closeShift(shiftId: string, cmd: CloseShiftRequest): Observable { - return this.gateway.post(`/api/v1/sales/shifts/${shiftId}/close`, cmd); - } - - getShiftsPaged(page = 1, pageSize = 20, status = 'all'): Observable { - return this.gateway.get('/api/v1/sales/shifts', { page, pageSize, status }); - } - - getShiftSummary(): Observable { - return this.gateway.get('/api/v1/sales/shifts/current/summary'); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS } from '../constants'; + +export interface SaleSummary { + saleId: string; + receiptNumber: string; + statusId: number; + total: number; + totalPaid: number; + createdAt: string; + itemCount: number; +} + +export interface PagedSalesResponse { + items: SaleSummary[]; + page: number; + pageSize: number; + totalCount: number; + totalPages: number; + totalRevenue: number; +} + +export interface CreateSaleItemRequest { + productId: string; + presentationId: string; + quantity: number; +} + +export interface CreateSalePaymentRequest { + paymentMethodId: number; + amount: number; + reference?: string; + customerId?: string; +} + +export interface DeliveryAddressRequest { + province: string; + sector: string; + street: string; + reference: string; + houseNumber?: string; + latitude?: number; + longitude?: number; +} + +export interface CreateSaleRequest { + items: CreateSaleItemRequest[]; + payments: CreateSalePaymentRequest[]; + notes?: string | null; + buyerRnc?: string | null; + deliveryAddress?: DeliveryAddressRequest | null; +} + +export interface CreateSaleLineResult { + productId: string; + productName: string; + quantity: number; + unitPrice: number; + lineItbis: number; + lineTotal: number; +} + +export interface CreateSaleResult { + saleId: string; + receiptNumber: string; + ncfNumber: string | null; + subtotal: number; + totalItbis: number; + total: number; + totalPaid: number; + changeDue: number; + items: CreateSaleLineResult[]; + deliveryOrderId?: string | null; + confirmationCode?: string | null; +} + +export interface ShiftDto { + shiftId: string; + tenantId: string; + terminalId: string; + cashierName: string; + status: string; + openingCashAmount: number; + closingCashAmount: number | null; + openedAt: string; + closedAt: string | null; + expectedCashAmount: number | null; + actualCashAmount: number | null; + cashDifference: number | null; + notes: string | null; + totalSalesCount: number; + totalSalesAmount: number; +} + +export interface ShiftSummaryDto { + shiftId: string; + openedAt: string; + openingCashAmount: number; + totalCashSales: number; + totalAccountPayments: number; + totalExpenses: number; + expectedCashAmount: number; +} + +export interface OpenShiftRequest { + openingCashAmount: number; + cashierName: string; +} + +export interface CloseShiftRequest { + actualCashAmount: number; + notes?: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class SaleService { + private gateway = inject(GatewayService); + + getSales(page = 1, pageSize = 10): Observable { + return this.gateway.get(API_PATHS.SALES, { page, pageSize }); + } + + createSale(cmd: CreateSaleRequest): Observable { + return this.gateway.post(API_PATHS.SALES, cmd); + } + + voidSale(id: string, reason: string): Observable { + return this.gateway.post(`${API_PATHS.SALES}/${id}/void`, { voidReason: reason }); + } + + getCurrentShift(): Observable { + return this.gateway.get(API_PATHS.SALES_SHIFTS_CURRENT); + } + + openShift(cmd: OpenShiftRequest): Observable<{ shiftId: string }> { + return this.gateway.post(API_PATHS.SALES_SHIFTS + '/open', cmd); + } + + closeShift(shiftId: string, cmd: CloseShiftRequest): Observable { + return this.gateway.post(`${API_PATHS.SALES_SHIFTS}/${shiftId}/close`, cmd); + } + + getShiftsPaged(page = 1, pageSize = 20, status = 'all'): Observable { + return this.gateway.get(API_PATHS.SALES_SHIFTS, { page, pageSize, status }); + } + + getShiftSummary(): Observable { + return this.gateway.get(API_PATHS.SALES_SHIFTS_SUMMARY); + } +} diff --git a/frontend/web-admin/src/app/core/services/settings.service.ts b/frontend/web-admin/src/app/core/services/settings.service.ts index 9bb821e..78433b5 100644 --- a/frontend/web-admin/src/app/core/services/settings.service.ts +++ b/frontend/web-admin/src/app/core/services/settings.service.ts @@ -1,32 +1,33 @@ -import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { GatewayService } from './gateway.service'; - -export interface TenantProfileDto { - businessName: string; - rnc: string | null; - businessAddress: string; - phone: string | null; - email: string | null; -} - -export interface UpsertTenantProfileRequest { - businessName: string; - rnc: string | null; - businessAddress: string; - phone: string | null; - email: string | null; -} - -@Injectable({ providedIn: 'root' }) -export class SettingsService { - private gateway = inject(GatewayService); - - getProfile(): Observable { - return this.gateway.get('/api/v1/settings/profile'); - } - - upsertProfile(req: UpsertTenantProfileRequest): Observable { - return this.gateway.put('/api/v1/settings/profile', req); - } -} +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { GatewayService } from './gateway.service'; +import { API_PATHS } from '../constants'; + +export interface TenantProfileDto { + businessName: string; + rnc: string | null; + businessAddress: string; + phone: string | null; + email: string | null; +} + +export interface UpsertTenantProfileRequest { + businessName: string; + rnc: string | null; + businessAddress: string; + phone: string | null; + email: string | null; +} + +@Injectable({ providedIn: 'root' }) +export class SettingsService { + private gateway = inject(GatewayService); + + getProfile(): Observable { + return this.gateway.get(API_PATHS.SETTINGS_PROFILE); + } + + upsertProfile(req: UpsertTenantProfileRequest): Observable { + return this.gateway.put(API_PATHS.SETTINGS_PROFILE, req); + } +} diff --git a/frontend/web-admin/src/app/core/services/theme.service.ts b/frontend/web-admin/src/app/core/services/theme.service.ts index 7ef6dba..56eb8c6 100644 --- a/frontend/web-admin/src/app/core/services/theme.service.ts +++ b/frontend/web-admin/src/app/core/services/theme.service.ts @@ -1,23 +1,24 @@ -import { Injectable, signal } from '@angular/core'; - -@Injectable({ providedIn: 'root' }) -export class ThemeService { - currentTheme = signal<'tucolmadodark' | 'tucolmadolight'>('tucolmadodark'); - - initTheme() { - const savedTheme = localStorage.getItem('tucolmado-theme') as 'tucolmadodark' | 'tucolmadolight'; - const themeToApply = savedTheme || 'tucolmadodark'; - this.setTheme(themeToApply); - } - - toggleTheme() { - const newTheme = this.currentTheme() === 'tucolmadodark' ? 'tucolmadolight' : 'tucolmadodark'; - this.setTheme(newTheme); - } - - private setTheme(theme: 'tucolmadodark' | 'tucolmadolight') { - this.currentTheme.set(theme); - localStorage.setItem('tucolmado-theme', theme); - document.documentElement.setAttribute('data-theme', theme); - } -} +import { Injectable, signal } from '@angular/core'; +import { LS_KEYS } from '../constants'; + +@Injectable({ providedIn: 'root' }) +export class ThemeService { + currentTheme = signal<'tucolmadodark' | 'tucolmadolight'>('tucolmadodark'); + + initTheme() { + const savedTheme = localStorage.getItem(LS_KEYS.THEME) as 'tucolmadodark' | 'tucolmadolight'; + const themeToApply = savedTheme || 'tucolmadodark'; + this.setTheme(themeToApply); + } + + toggleTheme() { + const newTheme = this.currentTheme() === 'tucolmadodark' ? 'tucolmadolight' : 'tucolmadodark'; + this.setTheme(newTheme); + } + + private setTheme(theme: 'tucolmadodark' | 'tucolmadolight') { + this.currentTheme.set(theme); + localStorage.setItem(LS_KEYS.THEME, theme); + document.documentElement.setAttribute('data-theme', theme); + } +} diff --git a/frontend/web-admin/src/app/features/portal/dashboard/dashboard.html b/frontend/web-admin/src/app/features/portal/dashboard/dashboard.html index feddb01..f2c4847 100644 --- a/frontend/web-admin/src/app/features/portal/dashboard/dashboard.html +++ b/frontend/web-admin/src/app/features/portal/dashboard/dashboard.html @@ -45,8 +45,8 @@ @if (!lowStockLoading && lowStock.count > 0) {
- @for (p of lowStock.items.slice(0, 2); track p.productId) { -

{{ p.name }}

+ @for (p of lowStock.items.slice(0, 2); track p.presentationId) { +

{{ p.productName }} — {{ p.presentationDisplayName }}

} @if (lowStock.count > 2) {

+{{ lowStock.count - 2 }} más

diff --git a/frontend/web-admin/src/app/features/portal/dashboard/dashboard.ts b/frontend/web-admin/src/app/features/portal/dashboard/dashboard.ts index 5d35276..f515aa5 100644 --- a/frontend/web-admin/src/app/features/portal/dashboard/dashboard.ts +++ b/frontend/web-admin/src/app/features/portal/dashboard/dashboard.ts @@ -44,7 +44,7 @@ export class Dashboard implements OnInit, OnDestroy { debtStats = { customersWithDebt: 0, totalDebt: 0 }; debtLoading = true; - lowStock: { count: number; items: { productId: string; name: string; stockQuantity: number }[] } = { count: 0, items: [] }; + lowStock: { count: number; items: { presentationId: string; productName: string; presentationDisplayName: string; stockQuantity: number }[] } = { count: 0, items: [] }; lowStockLoading = true; // Turno activo @@ -112,8 +112,8 @@ export class Dashboard implements OnInit, OnDestroy { loadLowStock(): void { this.lowStockLoading = true; - this.inventoryService.getLowStock(5).subscribe({ - next: data => { + this.inventoryService.getLowStockPresentations().subscribe({ + next: (data) => { this.lowStock = data; this.lowStockLoading = false; }, diff --git a/frontend/web-admin/src/app/features/portal/inventory/inventory.html b/frontend/web-admin/src/app/features/portal/inventory/inventory.html index 05bb63a..bbf945e 100644 --- a/frontend/web-admin/src/app/features/portal/inventory/inventory.html +++ b/frontend/web-admin/src/app/features/portal/inventory/inventory.html @@ -1,358 +1,210 @@ -
- - -
-
-

Inventario

-

Gestión de productos y stock del colmado

-
- -
- - -
-
-

Total Productos

-

{{ totalProducts() }}

-
-
-

Stock Crítico (≤5)

-

{{ lowStockProducts() }}

-
-
-

Activos

-

{{ activeProducts() }}

-
-
- - -
- -
-
- -

Catálogo de Productos

-
-
- - -
-
- - - @if (errorMsg()) { -
{{ errorMsg() }}
- } - -
- - - - - - - - - - - - - - - @if (loading()) { - @for (i of [1,2,3,4,5,6,7,8]; track i) { - - - - } - } @else if (products().length === 0) { - - - - } @else { - @for (product of products(); track product.productId; let odd = $odd) { - - - - - - - - - - - } - } - -
ProductoCategoríaCostoPrecio VentaStockITBISEstadoAcciones
- -

Sin productos registrados

-

Haz clic en "Nuevo Producto" para agregar el primero.

-
-
- {{ product.name }} - {{ unitTypeLabel(product.unitTypeId) }} -
-
{{ product.categoryName }}{{ product.costPrice | rdCurrency }}{{ product.salePrice | rdCurrency }} - {{ product.stockQuantity | number:'1.0-2' }} - {{ (product.itbisRate * 100) | number:'1.0-0' }}% - @if (product.isActive) { - Activo - } @else { - Inactivo - } - -
- - - @if (product.isActive) { - - } -
-
-
- - - @if (totalPages() > 1) { -
- Página {{ page() }} de {{ totalPages() }} · {{ totalCount() }} productos -
- - -
-
- } -
-
- - - - -@if (modalMode() === 'create') { -
-
-
-

Nuevo Producto

- -
-
- @if (errorMsg()) { -
{{ errorMsg() }}
- } -
- - -
-
- - @if (loadingCategories()) { -
- } @else if (categories().length === 0) { -

- No hay categorías. Créalas aquí → -

- } @else { - - } -
-
-
- - -
-
- - - @if (createForm.errors?.['saleBelowCost']) { -

El precio de venta es menor al costo.

- } -
-
-
-
- - -
-
- - -
-
-
- - -
-
-
-
-} - - -@if (modalMode() === 'edit-price') { -
-
-
-
-

Actualizar Precio

-

{{ selectedProduct()?.name }}

-
- -
-
- @if (errorMsg()) { -
{{ errorMsg() }}
- } -
- - -
-
- - -
-
- - -
-
-
-
-} - - -@if (modalMode() === 'adjust-stock') { -
-
-
-
-

Movimiento de Stock

-

{{ selectedProduct()?.name }} · Stock actual: {{ selectedProduct()?.stockQuantity }}

-
- -
-
- @if (errorMsg()) { -
{{ errorMsg() }}
- } - - -
- -
- - -
-

- @if (adjustType() === 'compra') { - Registra la entrada de mercancía y genera un gasto automáticamente. - } @else { - Corrige el stock manualmente (merma, conteo, corrección). - } -

-
- - -
- - @if (adjustType() === 'ajuste') { -

Positivo para agregar, negativo para reducir

- } - -
- - - @if (adjustType() === 'compra') { -
-
- Gasto Calculado - {{ calculatedExpense() | rdCurrency }} -
-

- {{ stockForm.controls.delta.value | number:'1.0-2' }} × {{ selectedProduct()?.costPrice | rdCurrency }} (costo unitario) -

-
- - -

Si pagaste un monto distinto al calculado, ingrésalo aquí.

-
-
- } - - - @if (adjustType() === 'ajuste') { -
- - -
- } - -
- - -
-
-
-
-} +
+ + +
+
+

Inventario

+

Gestión de productos y presentaciones

+
+
+ + +
+
+ + +
+
+

Total Productos

+

{{ totalProducts() }}

+
+
+

Stock Crítico

+

{{ lowStockProducts() }}

+
+
+

Activos

+

{{ activeProducts() }}

+
+
+ + +
+ +
+
+ +

Catálogo de Productos

+
+
+ + +
+
+ + + @if (errorMsg()) { +
{{ errorMsg() }}
+ } + +
+ + + + + + + + + + + + + + @if (loading()) { + @for (i of [1,2,3,4,5,6,7,8]; track i) { + + + + } + } @else if (products().length === 0) { + + + + } @else { + @for (product of products(); track product.productId; let odd = $odd) { + + + + + + + + + + } + } + +
ProductoCategoríaPrecioStockPresentacionesEstadoAcciones
+ +

Sin productos registrados

+

Haz clic en "Nuevo Producto" para agregar el primero.

+
+
+ {{ product.name }} + @if (product.presentations && product.presentations.length > 0) { + {{ product.presentations.length }} presentaciones + } +
+
{{ product.categoryName }}{{ getPriceRange(product) }} + {{ getStockSummary(product) }} + + {{ product.presentations?.length ?? 0 }} + + @if (product.isActive) { + Activo + } @else { + Inactivo + } + +
+ + + + @if (product.isActive) { + + } +
+
+
+ + + @if (totalPages() > 1) { +
+ Página {{ page() }} de {{ totalPages() }} · {{ totalCount() }} productos +
+ + +
+
+ } +
+
+ + +@if (modalMode() === 'create') { +
+
+
+

Nuevo Producto

+ +
+
+ @if (errorMsg()) { +
{{ errorMsg() }}
+ } +
+ + +
+
+ + @if (loadingCategories()) { +
+ } @else if (categories().length === 0) { +

+ No hay categorías. Créalas aquí → +

+ } @else { + + } +
+
+
+ + +
+
+ + + @if (createForm.errors?.['saleBelowCost']) { +

El precio de venta es menor al costo.

+ } +
+
+
+ + +
+

Se creará una presentación predeterminada. Podrás agregar más desde la gestión de presentaciones.

+
+ + +
+
+
+
+} diff --git a/frontend/web-admin/src/app/features/portal/inventory/inventory.ts b/frontend/web-admin/src/app/features/portal/inventory/inventory.ts index cd4b061..35c8c8b 100644 --- a/frontend/web-admin/src/app/features/portal/inventory/inventory.ts +++ b/frontend/web-admin/src/app/features/portal/inventory/inventory.ts @@ -1,293 +1,223 @@ -import { Component, inject, OnInit, signal, computed } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterLink } from '@angular/router'; -import { ReactiveFormsModule, FormBuilder, Validators, AbstractControl, ValidationErrors } from '@angular/forms'; -import { - InventoryService, - ProductDto, - CreateProductRequest, - AdjustStockRequest, - CategoryDto, -} from '../../../core/services/inventory.service'; -import { ExpenseService } from '../../../core/services/expense.service'; -import { RdCurrencyPipe } from '../../../core/pipes'; - -type ModalMode = 'create' | 'edit-price' | 'adjust-stock' | null; - -function salePriceValidator(group: AbstractControl): ValidationErrors | null { - const cost = group.get('costPrice')?.value ?? 0; - const sale = group.get('salePrice')?.value ?? 0; - return sale > 0 && sale < cost ? { saleBelowCost: true } : null; -} - -const ERROR_MESSAGES: Record = { - 'product.sale_price_below_cost': 'El precio de venta no puede ser menor al costo.', - 'product.category_required': 'Selecciona una categoría.', - 'product.name_required': 'El nombre del producto es obligatorio.', - 'product.invalid_price': 'El precio ingresado no es válido.', - 'category.not_found': 'La categoría seleccionada no existe.', -}; - -function mapInventoryError(code?: string): string { - if (!code) return ''; - return ERROR_MESSAGES[code] ?? code; -} - -@Component({ - selector: 'app-inventory', - standalone: true, - imports: [CommonModule, RouterLink, ReactiveFormsModule, RdCurrencyPipe], - templateUrl: './inventory.html', -}) -export class Inventory implements OnInit { - private inventoryService = inject(InventoryService); - private expenseService = inject(ExpenseService); - private fb = inject(FormBuilder); - - // State - products = signal([]); - categories = signal([]); - loading = signal(true); - saving = signal(false); - errorMsg = signal(null); - - // Pagination - page = signal(1); - pageSize = signal(20); - totalCount = signal(0); - totalPages = signal(0); - searchQuery = signal(''); - - // Modal - modalMode = signal(null); - selectedProduct = signal(null); - - // Forms - createForm = this.fb.nonNullable.group({ - name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(120)]], - costPrice: [0, [Validators.required, Validators.min(0)]], - salePrice: [0, [Validators.required, Validators.min(0.01)]], - itbisRate: [0.18, [Validators.required, Validators.min(0), Validators.max(1)]], - unitType: [1, Validators.required], - categoryId: ['', Validators.required], - }, { validators: salePriceValidator }); - - priceForm = this.fb.nonNullable.group({ - newCostPrice: [0, [Validators.required, Validators.min(0)]], - newSalePrice: [0, [Validators.required, Validators.min(0.01)]], - }); - - adjustType = signal<'compra' | 'ajuste'>('ajuste'); - - stockForm = this.fb.nonNullable.group({ - delta: [0, [Validators.required, Validators.min(0.001)]], - reason: [''], - expenseAmount: [0, [Validators.min(0)]], - }); - - calculatedExpense = computed(() => { - const product = this.selectedProduct(); - const delta = this.stockForm.controls.delta.value ?? 0; - if (!product || this.adjustType() !== 'compra' || delta <= 0) return 0; - return Math.round(delta * product.costPrice * 100) / 100; - }); - - // Computed stats - totalProducts = computed(() => this.totalCount()); - lowStockProducts = computed(() => this.products().filter(p => p.stockQuantity <= 5).length); - activeProducts = computed(() => this.products().filter(p => p.isActive).length); - - ngOnInit(): void { - this.loadProducts(); - this.loadCategories(); - } - - loadingCategories = signal(false); - - loadCategories(): void { - this.loadingCategories.set(true); - this.inventoryService.getCategories().subscribe({ - next: (cats) => { this.categories.set(cats); this.loadingCategories.set(false); }, - error: () => this.loadingCategories.set(false), - }); - } - - loadProducts(): void { - this.loading.set(true); - this.errorMsg.set(null); - this.inventoryService.getProducts(this.page(), this.pageSize(), this.searchQuery() || undefined).subscribe({ - next: (res) => { - this.products.set(res.items); - this.totalCount.set(res.totalCount); - this.totalPages.set(res.totalPages); - this.loading.set(false); - }, - error: (err) => { - this.errorMsg.set(err?.error?.message || 'Error cargando productos.'); - this.loading.set(false); - } - }); - } - - onSearch(event: Event): void { - const val = (event.target as HTMLInputElement).value; - this.searchQuery.set(val); - this.page.set(1); - this.loadProducts(); - } - - nextPage(): void { - if (this.page() < this.totalPages()) { - this.page.update(p => p + 1); - this.loadProducts(); - } - } - - prevPage(): void { - if (this.page() > 1) { - this.page.update(p => p - 1); - this.loadProducts(); - } - } - - // --- Modal openers --- - openCreate(): void { - this.selectedProduct.set(null); - this.errorMsg.set(null); - this.modalMode.set('create'); - this.loadingCategories.set(true); - this.inventoryService.getCategories().subscribe({ - next: (cats) => { - this.categories.set(cats); - this.loadingCategories.set(false); - this.createForm.reset({ itbisRate: 0.18, unitType: 1, categoryId: cats[0]?.id ?? '' }); - }, - error: () => this.loadingCategories.set(false), - }); - } - - openEditPrice(product: ProductDto): void { - this.selectedProduct.set(product); - this.priceForm.reset({ newCostPrice: product.costPrice, newSalePrice: product.salePrice }); - this.modalMode.set('edit-price'); - this.errorMsg.set(null); - } - - openAdjustStock(product: ProductDto): void { - this.selectedProduct.set(product); - this.adjustType.set('ajuste'); - this.stockForm.reset({ delta: 0, reason: '', expenseAmount: 0 }); - this.modalMode.set('adjust-stock'); - this.errorMsg.set(null); - } - - setAdjustType(type: 'compra' | 'ajuste'): void { - this.adjustType.set(type); - this.stockForm.patchValue({ reason: '', expenseAmount: 0 }); - } - - closeModal(): void { - this.modalMode.set(null); - this.selectedProduct.set(null); - this.errorMsg.set(null); - } - - // --- Submit handlers --- - submitCreate(): void { - if (this.createForm.invalid) { this.createForm.markAllAsTouched(); return; } - this.saving.set(true); - const v = this.createForm.getRawValue(); - const cmd: CreateProductRequest = { - name: v.name, - categoryId: v.categoryId, - costPrice: v.costPrice, - salePrice: v.salePrice, - itbisRate: v.itbisRate, - unitType: v.unitType, - }; - this.inventoryService.createProduct(cmd).subscribe({ - next: () => { this.saving.set(false); this.closeModal(); this.loadProducts(); }, - error: (err) => { this.saving.set(false); this.errorMsg.set(mapInventoryError(err?.error?.error ?? err?.error?.message) || 'Error creando producto.'); } - }); - } - - submitPrice(): void { - if (this.priceForm.invalid || !this.selectedProduct()) return; - this.saving.set(true); - const v = this.priceForm.getRawValue(); - this.inventoryService.updatePrice(this.selectedProduct()!.productId, v).subscribe({ - next: () => { this.saving.set(false); this.closeModal(); this.loadProducts(); }, - error: (err) => { this.saving.set(false); this.errorMsg.set(err?.error?.message || 'Error actualizando precio.'); } - }); - } - - submitStock(): void { - const product = this.selectedProduct(); - if (!product) return; - const v = this.stockForm.getRawValue(); - if (v.delta <= 0 && this.adjustType() === 'compra') { - this.errorMsg.set('La cantidad debe ser mayor a 0 para registrar una compra.'); - return; - } - if (this.adjustType() === 'ajuste' && !v.reason.trim()) { - this.stockForm.controls.reason.setErrors({ required: true }); - this.stockForm.markAllAsTouched(); - return; - } - this.saving.set(true); - const reason = this.adjustType() === 'compra' - ? `Compra de ${v.delta} ${this.unitTypeLabel(product.unitTypeId)} de ${product.name}` - : v.reason; - const req: AdjustStockRequest = { delta: v.delta, reason }; - this.inventoryService.adjustStock(product.productId, req).subscribe({ - next: () => { - if (this.adjustType() === 'compra') { - const amount = v.expenseAmount > 0 ? v.expenseAmount : this.calculatedExpense(); - this.expenseService.registerExpense({ - amount, - category: 'Compra de Inventario', - description: reason, - }).subscribe({ - next: () => { this.saving.set(false); this.closeModal(); this.loadProducts(); }, - error: () => { this.saving.set(false); this.closeModal(); this.loadProducts(); }, - }); - } else { - this.saving.set(false); this.closeModal(); this.loadProducts(); - } - }, - error: (err) => { this.saving.set(false); this.errorMsg.set(err?.error?.message || 'Error ajustando stock.'); } - }); - } - - deactivate(product: ProductDto): void { - if (!confirm(`¿Desactivar "${product.name}"? Ya no aparecerá en ventas.`)) return; - this.inventoryService.deactivateProduct(product.productId).subscribe({ - next: () => this.loadProducts(), - error: (err) => alert(err?.error?.message || 'Error desactivando producto.') - }); - } - - getStockClass(qty: number): string { - if (qty <= 0) return 'text-red-500'; - if (qty <= 5) return 'text-amber-400'; - return 'text-green-400'; - } - - readonly unitTypes = [ - { id: 1, name: 'Unidad' }, - { id: 2, name: 'Libra' }, - { id: 3, name: 'Litro' }, - { id: 4, name: 'Caja' }, - ]; - - private static readonly UNIT_LABELS: Record = { - 1: 'Unidad', - 2: 'Libra', - 3: 'Litro', - 4: 'Caja', - }; - - unitTypeLabel(id: number): string { - return Inventory.UNIT_LABELS[id] ?? 'Unidad'; - } -} +import { Component, inject, OnInit, signal, computed } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterLink } from '@angular/router'; +import { ReactiveFormsModule, FormBuilder, Validators, AbstractControl, ValidationErrors } from '@angular/forms'; +import { InventoryService, CategoryDto } from '../../../core/services/inventory.service'; +import { DEFAULT_ITBIS_RATE, LOW_STOCK_THRESHOLD } from '../../../core/constants'; +import type { ProductDto } from '../../../core/models/inventory.models'; + +function salePriceValidator(group: AbstractControl): ValidationErrors | null { + const cost = group.get('costPrice')?.value ?? 0; + const sale = group.get('salePrice')?.value ?? 0; + return sale > 0 && sale < cost ? { saleBelowCost: true } : null; +} + +const ERROR_MESSAGES: Record = { + 'product.sale_price_below_cost': 'El precio de venta no puede ser menor al costo.', + 'product.category_required': 'Selecciona una categoría.', + 'product.name_required': 'El nombre del producto es obligatorio.', + 'product.invalid_price': 'El precio ingresado no es válido.', + 'category.not_found': 'La categoría seleccionada no existe.', +}; + +function mapInventoryError(code?: string): string { + if (!code) return ''; + return ERROR_MESSAGES[code] ?? code; +} + +@Component({ + selector: 'app-inventory', + standalone: true, + imports: [CommonModule, RouterLink, ReactiveFormsModule], + templateUrl: './inventory.html', +}) +export class Inventory implements OnInit { + private inventoryService = inject(InventoryService); + private fb = inject(FormBuilder); + + products = signal([]); + categories = signal([]); + loading = signal(true); + saving = signal(false); + errorMsg = signal(null); + + page = signal(1); + pageSize = signal(20); + totalCount = signal(0); + totalPages = signal(0); + searchQuery = signal(''); + + modalMode = signal<'create' | null>(null); + + createForm = this.fb.nonNullable.group({ + name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(120)]], + costPrice: [0, [Validators.required, Validators.min(0)]], + salePrice: [0, [Validators.required, Validators.min(0.01)]], + itbisRate: [DEFAULT_ITBIS_RATE, [Validators.required, Validators.min(0), Validators.max(1)]], + categoryId: ['', Validators.required], + }, { validators: salePriceValidator }); + + totalProducts = computed(() => this.totalCount()); + lowStockProducts = computed(() => { + let count = 0; + for (const p of this.products()) { + for (const pres of p.presentations ?? []) { + if (pres.stockQuantity <= LOW_STOCK_THRESHOLD) { count++; break; } + } + } + return count; + }); + activeProducts = computed(() => this.products().filter(p => p.isActive).length); + + ngOnInit(): void { + this.loadProducts(); + this.loadCategories(); + } + + loadingCategories = signal(false); + + loadCategories(): void { + this.loadingCategories.set(true); + this.inventoryService.getCategories().subscribe({ + next: (cats) => { this.categories.set(cats); this.loadingCategories.set(false); }, + error: () => this.loadingCategories.set(false), + }); + } + + loadProducts(): void { + this.loading.set(true); + this.errorMsg.set(null); + this.inventoryService.getProducts(this.page(), this.pageSize(), this.searchQuery() || undefined).subscribe({ + next: (res) => { + this.products.set(res.items); + this.totalCount.set(res.totalCount); + this.totalPages.set(res.totalPages); + this.loading.set(false); + }, + error: (err) => { + this.errorMsg.set(err?.error?.message || 'Error cargando productos.'); + this.loading.set(false); + } + }); + } + + onSearch(event: Event): void { + const val = (event.target as HTMLInputElement).value; + this.searchQuery.set(val); + this.page.set(1); + this.loadProducts(); + } + + nextPage(): void { + if (this.page() < this.totalPages()) { + this.page.update(p => p + 1); + this.loadProducts(); + } + } + + prevPage(): void { + if (this.page() > 1) { + this.page.update(p => p - 1); + this.loadProducts(); + } + } + + openCreate(): void { + this.errorMsg.set(null); + this.modalMode.set('create'); + this.loadingCategories.set(true); + this.inventoryService.getCategories().subscribe({ + next: (cats) => { + this.categories.set(cats); + this.loadingCategories.set(false); + this.createForm.reset({ itbisRate: DEFAULT_ITBIS_RATE, categoryId: cats[0]?.id ?? '' }); + }, + error: () => this.loadingCategories.set(false), + }); + } + + closeModal(): void { + this.modalMode.set(null); + this.errorMsg.set(null); + } + + submitCreate(): void { + if (this.createForm.invalid) { this.createForm.markAllAsTouched(); return; } + this.saving.set(true); + const v = this.createForm.getRawValue(); + this.inventoryService.createProduct({ + name: v.name, + categoryId: v.categoryId, + itbisRate: v.itbisRate, + }).subscribe({ + next: (res) => { + this.inventoryService.addPresentation(res.productId, { + displayName: 'Predeterminada', + presentationType: 2, + sellMode: 1, + measureUnit: 1, + salePrice: v.salePrice, + costPrice: v.costPrice, + }).subscribe({ + next: () => { + this.saving.set(false); + this.closeModal(); + this.loadProducts(); + }, + error: () => { + this.saving.set(false); + this.closeModal(); + this.loadProducts(); + }, + }); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(mapInventoryError(err?.error?.error ?? err?.error?.message) || 'Error creando producto.'); + } + }); + } + + deactivate(product: ProductDto): void { + if (!confirm(`¿Desactivar "${product.name}"? Ya no aparecerá en ventas.`)) return; + this.inventoryService.deactivateProduct(product.productId).subscribe({ + next: () => this.loadProducts(), + error: (err) => alert(err?.error?.message || 'Error desactivando producto.') + }); + } + + getStockSummary(product: ProductDto): string { + const presentations = product.presentations ?? []; + const bulk = presentations.filter(p => p.presentationType === 1); + const packaged = presentations.filter(p => p.presentationType === 2); + const parts: string[] = []; + if (packaged.length > 0) { + const total = packaged.reduce((s, p) => s + p.packagedStockQuantity, 0); + parts.push(`${total} empacadas`); + } + if (bulk.length > 0) { + const total = bulk.reduce((s, p) => s + p.openContainersCount, 0); + parts.push(`${total} contenedores`); + } + return parts.length > 0 ? parts.join(', ') : 'Sin stock'; + } + + getPriceRange(product: ProductDto): string { + const presentations = product.presentations ?? []; + if (presentations.length === 0) return '—'; + if (presentations.length === 1) { + return presentations[0].salePrice.toFixed(2); + } + const prices = presentations.map(p => p.salePrice); + const min = Math.min(...prices); + const max = Math.max(...prices); + return `${min.toFixed(2)} — ${max.toFixed(2)}`; + } + + getStockClass(product: ProductDto): string { + const minStock = Math.min(...(product.presentations ?? []).map(p => p.stockQuantity)); + if (minStock <= 0) return 'text-red-500'; + if (minStock <= LOW_STOCK_THRESHOLD) return 'text-amber-400'; + return 'text-green-400'; + } +} diff --git a/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.html b/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.html new file mode 100644 index 0000000..15da765 --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.html @@ -0,0 +1,238 @@ +
+ +
+
+

Fondo Monetario

+

Capital del colmado para compras y operaciones

+
+ +
+ + + @if (errorMsg()) { +
{{ errorMsg() }}
+ } + @if (successMsg()) { +
{{ successMsg() }}
+ } + + +
+
+
{{ totalBalance() | rdCurrency }}
+
Balance total
+
+
+
{{ activeFundCount() }}
+
Fondos activos
+
+
+ + +
+ @for (f of funds(); track f.id) { +
+
+

{{ f.name }}

+
{{ f.currentBalance | rdCurrency }}
+
Creado: {{ f.createdAt | date:'shortDate' }}
+
+
+ } @empty { +
+ No hay fondos. Crea el primero para comenzar. +
+ } +
+ + + @if (selectedFund()) { +
+
+
+
+

{{ selectedFund()!.fund.name }}

+
{{ selectedFund()!.fund.currentBalance | rdCurrency }}
+
+
+ + +
+
+ + +
Transacciones recientes
+
+ + + + + + + + + + + + + @for (t of transactions(); track t.id) { + + + + + + + + + } @empty { + + } + +
FechaTipoCategoríaDescripciónMontoBalance después
{{ fmtDate(t.occurredAt) }} + + {{ transactionTypeLabel(t.type) }} + + {{ categoryLabel(t.category) }} +
{{ t.description }}
+ @if (t.justificationNote) { +
Just: {{ t.justificationNote }}
+ } +
+ {{ t.type === 1 ? '+' : '-' }}{{ t.amount | rdCurrency }} + {{ t.balanceAfter | rdCurrency }}
No hay transacciones.
+
+ + + @if (totalPages() > 1) { +
+ {{ totalCount() }} transacciones +
+ + + +
+
+ } +
+
+ } + + + @if (showCreateModal()) { + + } + + + @if (showDepositModal()) { + + } + + + @if (showExpenseModal()) { + + } +
diff --git a/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.ts b/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.ts new file mode 100644 index 0000000..da80f38 --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/monetary-fund/monetary-fund.ts @@ -0,0 +1,229 @@ +import { Component, inject, OnInit, signal, computed } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms'; +import { MonetaryFundService, MonetaryFundDto, FundTransactionDto, FundBalanceResponse } from '../../../core/services/monetary-fund.service'; +import { RdCurrencyPipe } from '../../../core/pipes'; +import { + FUND_TRANSACTION_TYPE, FUND_TRANSACTION_TYPE_LABELS, + EXPENSE_CATEGORY, EXPENSE_CATEGORY_LABELS, + DEFAULT_PAGE_SIZE, +} from '../../../core/constants'; + +@Component({ + selector: 'app-monetary-fund', + standalone: true, + imports: [CommonModule, ReactiveFormsModule, RdCurrencyPipe], + templateUrl: './monetary-fund.html', +}) +export class MonetaryFund implements OnInit { + private fundService = inject(MonetaryFundService); + private fb = inject(FormBuilder); + + funds = signal([]); + selectedFund = signal(null); + transactions = signal([]); + loading = signal(true); + saving = signal(false); + errorMsg = signal(null); + successMsg = signal(null); + + showCreateModal = signal(false); + showDepositModal = signal(false); + showExpenseModal = signal(false); + + page = signal(1); + totalCount = signal(0); + totalPages = signal(0); + + createForm = this.fb.nonNullable.group({ + name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(80)]], + initialDeposit: [0, [Validators.required, Validators.min(0)]], + }); + + depositForm = this.fb.nonNullable.group({ + amount: [0, [Validators.required, Validators.min(0.01)]], + description: ['', [Validators.required, Validators.minLength(3)]], + }); + + expenseForm = this.fb.nonNullable.group({ + amount: [0, [Validators.required, Validators.min(0.01)]], + category: [EXPENSE_CATEGORY.OPERATIONAL, Validators.required], + description: ['', [Validators.required, Validators.minLength(3)]], + justificationNote: [''], + }); + + readonly expenseCategories = Object.entries(EXPENSE_CATEGORY).map(([key, value]) => ({ + key, value, label: EXPENSE_CATEGORY_LABELS[value as number] + })); + + totalBalance = computed(() => this.funds().reduce((s, f) => s + f.currentBalance, 0)); + activeFundCount = computed(() => this.funds().length); + + ngOnInit(): void { + this.loadFunds(); + } + + loadFunds(): void { + this.loading.set(true); + this.fundService.getFunds().subscribe({ + next: funds => { this.funds.set(funds); this.loading.set(false); }, + error: () => this.loading.set(false), + }); + } + + selectFund(fund: MonetaryFundDto): void { + this.selectedFund.set(null); + this.transactions.set([]); + this.fundService.getFund(fund.id).subscribe({ + next: data => { + this.selectedFund.set(data); + this.transactions.set(data.recentTransactions ?? []); + }, + error: () => {}, + }); + } + + loadTransactions(fundId: string): void { + this.fundService.getTransactions(fundId, this.page(), DEFAULT_PAGE_SIZE).subscribe({ + next: res => { + this.transactions.set(res.items); + this.totalCount.set(res.totalCount); + this.totalPages.set(res.totalPages); + }, + error: () => {}, + }); + } + + openCreate(): void { + this.errorMsg.set(null); + this.createForm.reset({ name: '', initialDeposit: 0 }); + this.showCreateModal.set(true); + } + + openDeposit(): void { + this.errorMsg.set(null); + this.depositForm.reset({ amount: 0, description: '' }); + this.showDepositModal.set(true); + } + + openExpense(): void { + this.errorMsg.set(null); + this.expenseForm.reset({ amount: 0, category: EXPENSE_CATEGORY.OPERATIONAL, description: '', justificationNote: '' }); + this.showExpenseModal.set(true); + } + + closeModals(): void { + this.showCreateModal.set(false); + this.showDepositModal.set(false); + this.showExpenseModal.set(false); + } + + submitCreate(): void { + if (this.createForm.invalid || this.saving()) { this.createForm.markAllAsTouched(); return; } + this.saving.set(true); + this.errorMsg.set(null); + const v = this.createForm.getRawValue(); + this.fundService.createFund({ name: v.name, initialDeposit: v.initialDeposit }).subscribe({ + next: () => { + this.saving.set(false); + this.successMsg.set(`Fondo "${v.name}" creado.`); + this.closeModals(); + this.loadFunds(); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(err?.error?.detail ?? err?.error?.message ?? 'Error creando fondo.'); + }, + }); + } + + submitDeposit(): void { + const fund = this.selectedFund(); + if (!fund || this.depositForm.invalid || this.saving()) { this.depositForm.markAllAsTouched(); return; } + this.saving.set(true); + this.errorMsg.set(null); + const v = this.depositForm.getRawValue(); + this.fundService.recordDeposit(fund.fund.id, { amount: v.amount, description: v.description }).subscribe({ + next: () => { + this.saving.set(false); + this.successMsg.set(`Depósito de ${v.amount | 0} registrado.`); + this.closeModals(); + this.selectFund(fund.fund); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(err?.error?.detail ?? err?.error?.message ?? 'Error registrando depósito.'); + }, + }); + } + + submitExpense(): void { + const fund = this.selectedFund(); + if (!fund || this.expenseForm.invalid || this.saving()) { this.expenseForm.markAllAsTouched(); return; } + this.saving.set(true); + this.errorMsg.set(null); + const v = this.expenseForm.getRawValue(); + const currentBalance = fund.fund.currentBalance; + + if (v.amount > currentBalance && !v.justificationNote.trim()) { + this.errorMsg.set('Debes incluir una justificación si el gasto excede el balance.'); + this.saving.set(false); + return; + } + + this.fundService.recordExpense(fund.fund.id, { + amount: v.amount, + category: v.category, + description: v.description, + justificationNote: v.justificationNote || null, + }).subscribe({ + next: () => { + this.saving.set(false); + this.successMsg.set('Gasto registrado.'); + this.closeModals(); + this.selectFund(fund.fund); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(err?.error?.detail ?? err?.error?.message ?? 'Error registrando gasto.'); + }, + }); + } + + transactionTypeLabel(type: number): string { + return FUND_TRANSACTION_TYPE_LABELS[type] ?? String(type); + } + + transactionTypeColor(type: number): string { + return type === FUND_TRANSACTION_TYPE.DEPOSIT + ? 'text-green-400' + : 'text-red-400'; + } + + categoryLabel(cat: number | null): string { + if (cat === null) return '—'; + return EXPENSE_CATEGORY_LABELS[cat] ?? String(cat); + } + + fmtDate(d: string): string { + return new Intl.DateTimeFormat('es-DO', { + day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' + }).format(new Date(d)); + } + + nextPage(): void { + if (this.page() < this.totalPages()) { + this.page.update(p => p + 1); + const fund = this.selectedFund(); + if (fund) this.loadTransactions(fund.fund.id); + } + } + + prevPage(): void { + if (this.page() > 1) { + this.page.update(p => p - 1); + const fund = this.selectedFund(); + if (fund) this.loadTransactions(fund.fund.id); + } + } +} diff --git a/frontend/web-admin/src/app/features/portal/presentations/presentations.html b/frontend/web-admin/src/app/features/portal/presentations/presentations.html new file mode 100644 index 0000000..1f75544 --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/presentations/presentations.html @@ -0,0 +1,257 @@ +
+ +
+
+

Presentaciones — {{ productName() }}

+

Gestiona las formas en que vendes este producto

+
+ +
+ + +
+
+
{{ totalPresentations() }}
+
Total presentaciones
+
+
+
{{ activePresentations() }}
+
Activas
+
+
+
{{ totalPackagedStock() }}
+
Unidades empacadas
+
+
+
{{ totalOpenContainers() }}
+
Contenedores abiertos
+
+
+ + + @if (errorMsg()) { +
{{ errorMsg() }}
+ } + @if (successMsg()) { +
{{ successMsg() }}
+ } + + +
+
+ @if (loading()) { +
+ } @else { +
+ + + + + + + + + + + + + + + + @for (p of presentations(); track p.id) { + + + + + + + + + + + + } @empty { + + } + +
PresentaciónTipoModo ventaMarcaCostoVentaStockEstadoAcciones
+
{{ p.displayName }}
+ @if (p.nominalCapacity) { +
{{ p.nominalCapacity }} {{ unitLabel(p.measureUnit) }}
+ } +
{{ presentationTypeLabel(p.presentationType) }}{{ sellModeLabel(p.sellMode) }}{{ p.brand ?? '—' }}{{ p.costPrice | rdCurrency }}{{ p.salePrice | rdCurrency }} + @if (p.presentationType === 2) { + {{ p.packagedStockQuantity }} uds + } @else { + {{ p.openContainersCount }} cont. + } + + @if (p.isActive) { + Activa + } @else { + Inactiva + } + +
+ @if (p.presentationType === 1) { + + } + + @if (p.isActive) { + + } +
+
No hay presentaciones. Crea la primera.
+
+ } +
+
+ + + @if (selectedPresentation() && containers().length > 0) { +
+
+
+

Contenedores — {{ selectedPresentation()?.displayName }}

+ +
+ @if (loadingContainers()) { +
+ } @else { +
+ @for (c of containers(); track c.id) { +
+
+
+ {{ c.containerCode }} + {{ containerStatusLabel(c.status) }} +
+
+
Capacidad: {{ c.nominalCapacity }} {{ unitLabel(selectedPresentation()?.measureUnit ?? 1) }}
+ @if (c.actualCapacity) { +
Peso real: {{ c.actualCapacity }}
+ } +
Restante: {{ c.currentRemaining | number:'1.2-2' }}
+ @if (c.isActiveSource) { +
← Contenedor activo
+ } + @if (c.openedAt) { +
Abierto: {{ fmtDate(c.openedAt) }}
+ } +
+
+ @if (c.status === 1) { + + } + @if (c.status === 2) { + + } +
+
+
+ } +
+ } +
+
+ } + + + @if (showModal()) { + + } +
diff --git a/frontend/web-admin/src/app/features/portal/presentations/presentations.ts b/frontend/web-admin/src/app/features/portal/presentations/presentations.ts new file mode 100644 index 0000000..8768d3e --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/presentations/presentations.ts @@ -0,0 +1,225 @@ +import { Component, inject, OnInit, signal, computed } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { InventoryService } from '../../../core/services/inventory.service'; +import { RdCurrencyPipe } from '../../../core/pipes'; +import type { ProductPresentationDto, StockContainerDto, CategoryDto } from '../../../core/services/inventory.service'; +import { + PRESENTATION_TYPE, PRESENTATION_TYPE_LABELS, + SELL_MODE, SELL_MODE_LABELS, + UNIT_OF_MEASURE, UNIT_OF_MEASURE_LABELS, + CONTAINER_STATUS, CONTAINER_STATUS_LABELS, +} from '../../../core/constants'; + +@Component({ + selector: 'app-presentations', + standalone: true, + imports: [CommonModule, ReactiveFormsModule, RdCurrencyPipe], + templateUrl: './presentations.html', +}) +export class Presentations implements OnInit { + private inventory = inject(InventoryService); + private fb = inject(FormBuilder); + private route = inject(ActivatedRoute); + + productId = signal(''); + productName = signal(''); + presentations = signal([]); + loading = signal(true); + saving = signal(false); + errorMsg = signal(null); + successMsg = signal(null); + showModal = signal(false); + selectedPresentation = signal(null); + containers = signal([]); + loadingContainers = signal(false); + + readonly presentationTypes = Object.entries(PRESENTATION_TYPE).map(([key, value]) => ({ + key, value, label: PRESENTATION_TYPE_LABELS[value as number] + })); + + readonly sellModes = Object.entries(SELL_MODE).map(([key, value]) => ({ + key, value, label: SELL_MODE_LABELS[value as number] + })); + + readonly unitsOfMeasure = Object.entries(UNIT_OF_MEASURE).map(([key, value]) => ({ + key, value, label: UNIT_OF_MEASURE_LABELS[value as number] + })); + + form = this.fb.group({ + displayName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(80)]], + presentationType: [2 as number, Validators.required], + sellMode: [1 as number, Validators.required], + brand: [''], + nominalCapacity: [0], + measureUnit: [1 as number, Validators.required], + salePrice: [0, [Validators.required, Validators.min(0.01)]], + costPrice: [0, [Validators.required, Validators.min(0)]], + }); + + isBulkContainer = computed(() => this.form.controls.presentationType.value === 1); + + totalPresentations = computed(() => this.presentations().length); + activePresentations = computed(() => this.presentations().filter(p => p.isActive).length); + totalPackagedStock = computed(() => this.presentations().reduce((s, p) => s + p.packagedStockQuantity, 0)); + totalOpenContainers = computed(() => this.presentations().reduce((s, p) => s + p.openContainersCount, 0)); + + ngOnInit(): void { + this.productId.set(this.route.snapshot.paramMap.get('id') ?? ''); + this.load(); + } + + load(): void { + this.loading.set(true); + this.inventory.getProductById(this.productId()).subscribe({ + next: product => { + this.productName.set(product.name); + this.presentations.set(product.presentations ?? []); + this.loading.set(false); + }, + error: () => this.loading.set(false), + }); + } + + openCreate(): void { + this.selectedPresentation.set(null); + this.errorMsg.set(null); + this.successMsg.set(null); + this.form.reset({ + displayName: '', + presentationType: 2, + sellMode: 1, + brand: '', + nominalCapacity: 0, + measureUnit: 1, + salePrice: 0, + costPrice: 0, + }); + this.showModal.set(true); + } + + openEdit(p: ProductPresentationDto): void { + this.selectedPresentation.set(p); + this.errorMsg.set(null); + this.successMsg.set(null); + this.form.patchValue({ + displayName: p.displayName, + presentationType: p.presentationType, + sellMode: p.sellMode, + brand: p.brand ?? '', + nominalCapacity: p.nominalCapacity ?? 0, + measureUnit: p.measureUnit, + salePrice: p.salePrice, + costPrice: p.costPrice, + }); + this.showModal.set(true); + } + + closeModal(): void { + this.showModal.set(false); + this.selectedPresentation.set(null); + } + + submit(): void { + if (this.form.invalid || this.saving()) { this.form.markAllAsTouched(); return; } + this.saving.set(true); + this.errorMsg.set(null); + const v = this.form.getRawValue(); + const pt = v.presentationType ?? 2; + const cmd = { + displayName: v.displayName ?? '', + presentationType: pt, + sellMode: v.sellMode ?? 1, + brand: v.brand || null, + nominalCapacity: pt === 1 ? (v.nominalCapacity ?? null) : null, + measureUnit: v.measureUnit ?? 1, + salePrice: v.salePrice ?? 0, + costPrice: v.costPrice ?? 0, + }; + + this.inventory.addPresentation(this.productId(), cmd).subscribe({ + next: () => { + this.saving.set(false); + this.successMsg.set(`Presentación "${v.displayName}" creada.`); + this.closeModal(); + this.load(); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(err?.error?.detail ?? err?.error?.message ?? 'Error al crear la presentación.'); + }, + }); + } + + deactivate(p: ProductPresentationDto): void { + if (!confirm(`¿Desactivar "${p.displayName}"?`)) return; + this.inventory.deactivatePresentation(p.id).subscribe({ + next: () => { this.successMsg.set('Presentación desactivada.'); this.load(); }, + error: (err) => this.errorMsg.set(err?.error?.message ?? 'Error desactivando.'), + }); + } + + viewContainers(p: ProductPresentationDto): void { + this.selectedPresentation.set(p); + this.loadingContainers.set(true); + this.inventory.getContainersByPresentation(p.id).subscribe({ + next: containers => { this.containers.set(containers); this.loadingContainers.set(false); }, + error: () => this.loadingContainers.set(false), + }); + } + + hideContainers(): void { + this.containers.set([]); + this.selectedPresentation.set(null); + } + + openContainer(containerId: string): void { + this.inventory.openContainer(containerId, {}).subscribe({ + next: () => { this.successMsg.set('Contenedor abierto.'); this.loadContainersForSelected(); }, + error: (err) => this.errorMsg.set(err?.error?.message ?? 'Error abriendo contenedor.'), + }); + } + + markContainerEmpty(containerId: string): void { + if (!confirm('¿Marcar este contenedor como vacío?')) return; + this.inventory.markContainerEmpty(containerId).subscribe({ + next: () => { this.successMsg.set('Contenedor marcado como vacío.'); this.loadContainersForSelected(); }, + error: (err) => this.errorMsg.set(err?.error?.message ?? 'Error marcando vacío.'), + }); + } + + private loadContainersForSelected(): void { + const p = this.selectedPresentation(); + if (p) this.viewContainers(p); + } + + presentationTypeLabel(type: number): string { + return PRESENTATION_TYPE_LABELS[type] ?? String(type); + } + + sellModeLabel(mode: number): string { + return SELL_MODE_LABELS[mode] ?? String(mode); + } + + unitLabel(unit: number): string { + return UNIT_OF_MEASURE_LABELS[unit] ?? String(unit); + } + + containerStatusLabel(status: number): string { + return CONTAINER_STATUS_LABELS[status] ?? String(status); + } + + containerStatusColor(status: number): string { + switch (status) { + case CONTAINER_STATUS.SEALED: return 'text-slate-400 bg-slate-500/10 ring-slate-500/20'; + case CONTAINER_STATUS.OPEN: return 'text-green-400 bg-green-500/10 ring-green-500/20'; + case CONTAINER_STATUS.EMPTY: return 'text-red-400 bg-red-500/10 ring-red-500/20'; + default: return 'text-slate-400'; + } + } + + fmtDate(d: string): string { + return new Intl.DateTimeFormat('es-DO', { day: '2-digit', month: 'short', year: 'numeric' }).format(new Date(d)); + } +} diff --git a/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.html b/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.html new file mode 100644 index 0000000..d3ed004 --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.html @@ -0,0 +1,173 @@ +
+ +
+
+

Entradas de Stock

+

Registra compras y recepciones de inventario

+
+ +
+ + + @if (errorMsg()) { +
{{ errorMsg() }}
+ } + @if (successMsg()) { +
{{ successMsg() }}
+ } + + +
+
+ @if (loading()) { +
+ } @else { +
+ + + + + + + + + + + + @for (e of entries(); track e.id) { + + + + + + + + } @empty { + + } + +
FechaProveedorLíneasCosto TotalNotas
{{ fmtDate(e.purchasedAt) }}{{ e.supplierName ?? '—' }}{{ e.lines.length }}{{ e.totalCost | rdCurrency }}{{ e.notes ?? '—' }}
No hay entradas registradas.
+
+ + + @if (totalPages() > 1) { +
+ {{ totalCount() }} entradas +
+ + + +
+
+ } + } +
+
+ + + @if (showModal()) { + + } +
diff --git a/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.ts b/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.ts new file mode 100644 index 0000000..2272eef --- /dev/null +++ b/frontend/web-admin/src/app/features/portal/stock-entries/stock-entries.ts @@ -0,0 +1,223 @@ +import { Component, inject, OnInit, signal, computed } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms'; +import { InventoryService, ProductPresentationDto, StockEntryDto } from '../../../core/services/inventory.service'; +import { MonetaryFundService, MonetaryFundDto } from '../../../core/services/monetary-fund.service'; +import { RdCurrencyPipe } from '../../../core/pipes'; +import { PRESENTATION_TYPE_LABELS, UNIT_OF_MEASURE_LABELS, DEFAULT_PAGE_SIZE } from '../../../core/constants'; + +interface EntryLineForm { + presentationId: string; + containerCount: number; + unitsPerContainer: number; + nominalSizePerUnit: number; + costPerUnit: number; +} + +@Component({ + selector: 'app-stock-entries', + standalone: true, + imports: [CommonModule, ReactiveFormsModule, RdCurrencyPipe], + templateUrl: './stock-entries.html', +}) +export class StockEntries implements OnInit { + private inventory = inject(InventoryService); + private fundService = inject(MonetaryFundService); + private fb = inject(FormBuilder); + + entries = signal([]); + presentations = signal([]); + funds = signal([]); + loading = signal(true); + saving = signal(false); + errorMsg = signal(null); + successMsg = signal(null); + showModal = signal(false); + + page = signal(1); + totalCount = signal(0); + totalPages = signal(0); + + entryForm = this.fb.group({ + purchasedAt: [new Date().toISOString().split('T')[0]], + supplierName: [''], + notes: [''], + fundId: [''], + lines: this.fb.nonNullable.array([]), + }); + + lineForms = signal([]); + + totalEntryCost = computed(() => + this.lineForms().reduce((s, l) => { + const units = l.containerCount * l.unitsPerContainer; + return s + units * l.costPerUnit; + }, 0) + ); + + ngOnInit(): void { + this.loadEntries(); + this.loadPresentations(); + this.loadFunds(); + } + + loadEntries(): void { + this.loading.set(true); + this.inventory.getStockEntries(this.page(), DEFAULT_PAGE_SIZE).subscribe({ + next: res => { + this.entries.set(res.items); + this.totalCount.set(res.totalCount); + this.totalPages.set(res.totalPages); + this.loading.set(false); + }, + error: () => this.loading.set(false), + }); + } + + loadPresentations(): void { + this.inventory.getCatalog().subscribe({ + next: products => { + const allPresentations: ProductPresentationDto[] = []; + for (const p of products) { + for (const pres of (p.presentations ?? [])) { + if (pres.isActive) { + (pres as any).productName = p.name; + allPresentations.push(pres); + } + } + } + this.presentations.set(allPresentations); + }, + error: () => {}, + }); + } + + loadFunds(): void { + this.fundService.getFunds().subscribe({ + next: funds => this.funds.set(funds), + error: () => {}, + }); + } + + openCreate(): void { + this.errorMsg.set(null); + this.successMsg.set(null); + this.lineForms.set([]); + this.entryForm.reset({ + purchasedAt: new Date().toISOString().split('T')[0], + supplierName: '', + notes: '', + fundId: '', + }); + this.showModal.set(true); + } + + closeModal(): void { + this.showModal.set(false); + } + + addLine(): void { + this.lineForms.update(lines => [...lines, { + presentationId: '', + containerCount: 1, + unitsPerContainer: 1, + nominalSizePerUnit: 1, + costPerUnit: 0, + }]); + } + + removeLine(index: number): void { + this.lineForms.update(lines => lines.filter((_, i) => i !== index)); + } + + updateLine(index: number, field: keyof EntryLineForm, value: string | number): void { + this.lineForms.update(lines => { + const updated = [...lines]; + updated[index] = { ...updated[index], [field]: value }; + return updated; + }); + } + + onPresentationChange(index: number, event: Event): void { + const value = (event.target as HTMLSelectElement).value; + this.updateLine(index, 'presentationId', value); + } + + onNumberInput(index: number, field: 'containerCount' | 'unitsPerContainer' | 'costPerUnit', event: Event): void { + const value = +(event.target as HTMLInputElement).value; + this.updateLine(index, field, value); + } + + getPresentationName(id: string): string { + const p = this.presentations().find(p => p.id === id); + if (!p) return ''; + return `${(p as any).productName ?? ''} — ${p.displayName}`; + } + + getLineTotal(line: EntryLineForm): number { + return line.containerCount * line.unitsPerContainer * line.costPerUnit; + } + + submit(): void { + const lines = this.lineForms(); + if (lines.length === 0) { + this.errorMsg.set('Agrega al menos una línea.'); + return; + } + for (const l of lines) { + if (!l.presentationId || l.containerCount <= 0 || l.costPerUnit <= 0) { + this.errorMsg.set('Completa todos los campos de cada línea.'); + return; + } + } + + this.saving.set(true); + this.errorMsg.set(null); + const v = this.entryForm.getRawValue(); + + this.inventory.confirmStockEntry({ + purchasedAt: v.purchasedAt ? new Date(v.purchasedAt).toISOString() : undefined, + supplierName: v.supplierName || null, + notes: v.notes || null, + fundId: v.fundId || null, + lines: lines.map(l => ({ + presentationId: l.presentationId, + containerCount: l.containerCount, + unitsPerContainer: l.unitsPerContainer, + nominalSizePerUnit: l.nominalSizePerUnit, + costPerUnit: l.costPerUnit, + })), + }).subscribe({ + next: () => { + this.saving.set(false); + this.successMsg.set('Entrada de stock registrada exitosamente.'); + this.closeModal(); + this.loadEntries(); + }, + error: (err) => { + this.saving.set(false); + this.errorMsg.set(err?.error?.detail ?? err?.error?.message ?? 'Error registrando entrada.'); + }, + }); + } + + nextPage(): void { + if (this.page() < this.totalPages()) { this.page.update(p => p + 1); this.loadEntries(); } + } + + prevPage(): void { + if (this.page() > 1) { this.page.update(p => p - 1); this.loadEntries(); } + } + + presentationTypeLabel(type: number): string { + return PRESENTATION_TYPE_LABELS[type] ?? String(type); + } + + unitLabel(unit: number): string { + return UNIT_OF_MEASURE_LABELS[unit] ?? String(unit); + } + + fmtDate(d: string): string { + return new Intl.DateTimeFormat('es-DO', { day: '2-digit', month: 'short', year: 'numeric' }).format(new Date(d)); + } +} diff --git a/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.component.html b/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.component.html index 5beea00..22ef43e 100644 --- a/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.component.html +++ b/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.component.html @@ -99,6 +99,22 @@

Tu licencia ha vencido

} + + + @if (!isSidebarCollapsed()) { + Entradas + } + + + + + @if (!isSidebarCollapsed()) { + Fondo + } + + diff --git a/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.ts b/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.ts index 24d058e..d9e7ce8 100644 --- a/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.ts +++ b/frontend/web-admin/src/app/layouts/portal-layout/portal-layout.ts @@ -6,8 +6,7 @@ import { filter } from 'rxjs/operators'; import { AuthService } from '../../core/services/auth.service'; import { SaleService, ShiftDto } from '../../core/services/sale.service'; import { DownloadService, DownloadInfo } from '../../core/services/download.service'; - -const BANNER_DISMISSED_KEY = 'tc_download_banner_dismissed'; +import { LS_KEYS } from '../../core/constants'; @Component({ selector: 'app-portal-layout', @@ -29,7 +28,7 @@ export class PortalLayout implements OnInit, OnDestroy { shiftElapsed = signal('--:--:--'); downloadInfo = signal(null); showDownloadBanner = signal( - localStorage.getItem(BANNER_DISMISSED_KEY) !== 'true' + localStorage.getItem(LS_KEYS.DOWNLOAD_BANNER_DISMISSED) !== 'true' ); isLicenseExpired = this.authService.isLicenseExpired; private router = inject(Router); @@ -64,7 +63,7 @@ export class PortalLayout implements OnInit, OnDestroy { } dismissBanner(): void { - localStorage.setItem(BANNER_DISMISSED_KEY, 'true'); + localStorage.setItem(LS_KEYS.DOWNLOAD_BANNER_DISMISSED, 'true'); this.showDownloadBanner.set(false); } diff --git a/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.html b/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.html index 4d60a60..7e1821d 100644 --- a/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.html +++ b/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.html @@ -128,19 +128,20 @@
} @else {
- @for (product of pagedCatalog(); track product.productId) { + @for (product of pagedCatalog(); track product.presentationId) { } @empty { @@ -923,7 +926,7 @@

@let calculatedQty = amount / priceWithTax;

- Se calculará: {{ calculatedQty | number:'1.0-3' }} {{ selected.unitTypeId === 2 ? 'lbs' : selected.unitTypeId === 3 ? 'L' : 'unidades' }} de {{ selected.name }} + Se calculará: {{ calculatedQty | number:'1.0-3' }} {{ selected.unitTypeId === 2 ? 'lbs' : selected.unitTypeId === 3 ? 'L' : 'unidades' }} de {{ selected.productName }} ({{ selected.displayName }})

} diff --git a/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.ts b/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.ts index 1c7e3fb..4aaba67 100644 --- a/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.ts +++ b/frontend/web-admin/src/app/layouts/pos-layout/pos-layout.ts @@ -10,10 +10,13 @@ import { InventoryService, ProductDto } from '../../core/services/inventory.serv import { CustomerService, CustomerSummary } from '../../core/services/customer.service'; import { SettingsService, TenantProfileDto } from '../../core/services/settings.service'; import { RdCurrencyPipe, RncPipe } from '../../core/pipes'; +import { PAYMENT_METHOD as PM, UNIT_TYPE, LOW_STOCK_THRESHOLD, CATALOG_PAGE_SIZE, PRODUCT_COLORS, NOMINATIM_BASE_URL, DR_LOCALE, DR_CURRENCY_CODE, WHATSAPP_BASE_URL, DEFAULT_CREDIT_LIMIT } from '../../core/constants'; export interface CartItem { productId: string; + presentationId: string; name: string; + displayName: string; salePrice: number; itbisRate: number; unitTypeId: number; @@ -23,8 +26,20 @@ export interface CartItem { lineTotal: number; } -/** Payment method IDs as defined in the backend PaymentMethod enum. */ -const PM = { Cash: 1, Card: 2, Transfer: 3, Credit: 4, Delivery: 5 } as const; +export interface CatalogPresentation { + productId: string; + productName: string; + presentationId: string; + displayName: string; + salePrice: number; + itbisRate: number; + unitTypeId: number; + stockQuantity: number; + categoryName: string; + presentationType: number; + sellMode: number; + isActive: boolean; +} @Component({ selector: 'app-pos-layout', @@ -49,7 +64,7 @@ export class PosLayout implements OnInit, OnDestroy { @ViewChild('cashTenderedInput') cashTenderedInput?: ElementRef; // ── Data signals ───────────────────────────────── - catalog = signal([]); + catalog = signal([]); cartItems = signal([]); activeShift = signal(null); lastSale = signal(null); @@ -89,10 +104,10 @@ export class PosLayout implements OnInit, OnDestroy { // ── Quick Sale ──────────────────────────────────── quickSaleSearch = signal(''); quickSaleAmount = signal(null); - selectedQuickProduct = signal(null); + selectedQuickProduct = signal(null); // ── Catalog pagination ──────────────────────────── - readonly PAGE_SIZE = 24; + readonly PAGE_SIZE = CATALOG_PAGE_SIZE; catalogPage = signal(0); @HostListener('window:keydown', ['$event']) @@ -127,7 +142,7 @@ export class PosLayout implements OnInit, OnDestroy { this.showCloseShiftModal.set(false); } - openQuickSaleModal(preselect?: ProductDto): void { + openQuickSaleModal(preselect?: CatalogPresentation): void { if (!this.activeShift()) { this.showOpenShiftModal.set(true); return; @@ -143,7 +158,7 @@ export class PosLayout implements OnInit, OnDestroy { const q = this.quickSaleSearch().toLowerCase().trim(); const sorted = [...this.catalog()].sort((a, b) => b.stockQuantity - a.stockQuantity); if (!q) return sorted.slice(0, 8); - return sorted.filter(p => p.name.toLowerCase().includes(q)).slice(0, 8); + return sorted.filter(p => p.displayName.toLowerCase().includes(q) || p.productName.toLowerCase().includes(q)).slice(0, 8); }); submitQuickSale(): void { @@ -179,7 +194,7 @@ export class PosLayout implements OnInit, OnDestroy { fullName: ['', [Validators.required, Validators.minLength(3)]], phone: [''], documentId: ['', [Validators.required]], - creditLimit: [5000, [Validators.required, Validators.min(0)]], + creditLimit: [DEFAULT_CREDIT_LIMIT, [Validators.required, Validators.min(0)]], province: [''], sector: [''], street: [''], @@ -206,15 +221,18 @@ export class PosLayout implements OnInit, OnDestroy { let items = this.catalog(); const q = this.catalogSearch().toLowerCase().trim(); const cat = this.selectedCategory(); - if (q) items = items.filter(p => p.name.toLowerCase().includes(q)); - if (cat) items = items.filter(p => p.categoryId === cat); + if (q) items = items.filter(p => p.displayName.toLowerCase().includes(q) || p.productName.toLowerCase().includes(q)); + if (cat) items = items.filter(p => p.categoryName === cat); return items; }); categories = computed(() => { const seen = new Map(); for (const p of this.catalog()) { - if (!seen.has(p.categoryId)) seen.set(p.categoryId, p.categoryName); + if (!seen.has(p.productName + '|' + p.categoryName)) { + const key = p.categoryName; + if (!seen.has(key)) seen.set(key, key); + } } return Array.from(seen.entries()).map(([id, name]) => ({ id, name })); }); @@ -245,11 +263,11 @@ export class PosLayout implements OnInit, OnDestroy { const phone = this.lastSaleCustomerPhone().replace(/\D/g, ''); const name = this.lastSaleCustomerName(); if (!sale?.confirmationCode || !phone) return null; - const total = new Intl.NumberFormat('es-DO', { style: 'currency', currency: 'DOP' }).format(sale.total); + const total = new Intl.NumberFormat(DR_LOCALE, { style: 'currency', currency: DR_CURRENCY_CODE }).format(sale.total); const text = encodeURIComponent( `Hola ${name}! Tu pedido de ${total} está en camino. Tu código de confirmación de entrega es: *${sale.confirmationCode}*. Dáselo al repartidor cuando recibas el pedido.` ); - return `https://wa.me/${phone}?text=${text}`; + return `${WHATSAPP_BASE_URL}/${phone}?text=${text}`; }); itbisBreakdown = computed(() => { @@ -288,7 +306,28 @@ export class PosLayout implements OnInit, OnDestroy { this.loading.set(true); this.inv.getCatalog().subscribe({ next: products => { - this.catalog.set(products.filter(p => p.isActive)); + const presentations: CatalogPresentation[] = []; + for (const p of products) { + if (!p.isActive) continue; + for (const pres of (p.presentations ?? [])) { + if (!pres.isActive) continue; + presentations.push({ + productId: p.productId, + productName: p.name, + presentationId: pres.id, + displayName: pres.displayName, + salePrice: pres.salePrice, + itbisRate: p.itbisRate, + unitTypeId: pres.measureUnit, + stockQuantity: pres.stockQuantity, + categoryName: p.categoryName, + presentationType: pres.presentationType, + sellMode: pres.sellMode, + isActive: pres.isActive, + }); + } + } + this.catalog.set(presentations); this.loading.set(false); }, error: () => this.loading.set(false) @@ -317,48 +356,49 @@ export class PosLayout implements OnInit, OnDestroy { } // ── Cart operations ─────────────────────────────── - updateStock(productId: string, delta: number): void { - this.catalog.update(cats => cats.map(p => - p.productId === productId ? { ...p, stockQuantity: p.stockQuantity + delta } : p + updateStock(presentationId: string, delta: number): void { + this.catalog.update(cats => cats.map(p => + p.presentationId === presentationId ? { ...p, stockQuantity: p.stockQuantity + delta } : p )); } - addToCart(product: ProductDto, customQuantity?: number): void { + addToCart(product: CatalogPresentation, customQuantity?: number): void { if (!this.activeShift()) { this.showOpenShiftModal.set(true); return; } - // Sold-by-weight or volume: open amount dialog so cashier enters RD$ value - if (customQuantity === undefined && (product.unitTypeId === 2 || product.unitTypeId === 3)) { + if (customQuantity === undefined && (product.sellMode === 2 || product.sellMode === 3)) { this.openQuickSaleModal(product); return; } const qtyToAdd = customQuantity ?? 1; const items = this.cartItems(); - const idx = items.findIndex(i => i.productId === product.productId); - + const idx = items.findIndex(i => i.presentationId === product.presentationId); + if (idx >= 0) { this.setQuantity(idx, items[idx].quantity + qtyToAdd); } else { const sub = product.salePrice * qtyToAdd; const itbis = sub * product.itbisRate; this.cartItems.set([...items, { - productId: product.productId, - name: product.name, - salePrice: product.salePrice, - itbisRate: product.itbisRate, - unitTypeId: product.unitTypeId, - quantity: qtyToAdd, - lineSubtotal: sub, - lineItbis: itbis, - lineTotal: sub + itbis + productId: product.productId, + presentationId: product.presentationId, + name: product.productName, + displayName: product.displayName, + salePrice: product.salePrice, + itbisRate: product.itbisRate, + unitTypeId: product.unitTypeId, + quantity: qtyToAdd, + lineSubtotal: sub, + lineItbis: itbis, + lineTotal: sub + itbis }]); - this.updateStock(product.productId, -qtyToAdd); + this.updateStock(product.presentationId, -qtyToAdd); } this.syncCashTendered(); - } + } setQuantity(index: number, qty: number): void { if (qty <= 0) { this.removeItem(index); return; } @@ -469,7 +509,7 @@ export class PosLayout implements OnInit, OnDestroy { `${c.street}${c.houseNumber ? ' ' + c.houseNumber : ''}, ${c.sector}, ${c.province}, República Dominicana` ); try { - const res = await fetch(`https://nominatim.openstreetmap.org/search?q=${query}&format=json&limit=1&countrycodes=do`); + const res = await fetch(`${NOMINATIM_BASE_URL}?q=${query}&format=json&limit=1&countrycodes=do`); const data = await res.json(); if (data?.length > 0) { this.selectedCustomer.update(prev => prev @@ -521,7 +561,7 @@ export class PosLayout implements OnInit, OnDestroy { houseNumber: v.houseNumber || null }); this.showAddCustomerModal.set(false); - this.customerForm.reset({ creditLimit: 5000 }); + this.customerForm.reset({ creditLimit: DEFAULT_CREDIT_LIMIT }); this.saving.set(false); }, error: e => { @@ -558,11 +598,11 @@ export class PosLayout implements OnInit, OnDestroy { this.saving.set(true); this.errorMsg.set(null); - const methodId = this.paymentMethod() === 'cash' ? PM.Cash - : this.paymentMethod() === 'card' ? PM.Card - : this.paymentMethod() === 'transfer' ? PM.Transfer - : this.paymentMethod() === 'credit' ? PM.Credit - : PM.Delivery; + const methodId = this.paymentMethod() === 'cash' ? PM.CASH + : this.paymentMethod() === 'card' ? PM.CARD + : this.paymentMethod() === 'transfer' ? PM.TRANSFER + : this.paymentMethod() === 'credit' ? PM.CREDIT + : PM.DELIVERY; let deliveryAddress = null; if (this.paymentMethod() === 'delivery') { @@ -596,7 +636,7 @@ export class PosLayout implements OnInit, OnDestroy { } this.sales.createSale({ - items: this.cartItems().map(i => ({ productId: i.productId, quantity: i.quantity })), + items: this.cartItems().map(i => ({ productId: i.productId, presentationId: i.presentationId, quantity: i.quantity })), payments: [{ paymentMethodId: methodId, amount: total, // For credit/delivery, the amount registered is the total @@ -644,8 +684,8 @@ export class PosLayout implements OnInit, OnDestroy { try { const res = await fetch( - `https://nominatim.openstreetmap.org/search?q=${query}&format=json&limit=1&countrycodes=do`, - { headers: { 'Accept-Language': 'es' } } + `${NOMINATIM_BASE_URL}?q=${query}&format=json&limit=1&countrycodes=do`, + { headers: { 'Accept-Language': DR_LOCALE } } ); const data = await res.json(); if (data?.length > 0) { @@ -663,7 +703,7 @@ export class PosLayout implements OnInit, OnDestroy { // ── Helpers ─────────────────────────────────────── fmtDate(d: Date | string = new Date()): string { - return new Intl.DateTimeFormat('es-DO', { + return new Intl.DateTimeFormat(DR_LOCALE, { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }).format(new Date(d)); @@ -697,11 +737,14 @@ export class PosLayout implements OnInit, OnDestroy { .toUpperCase(); } + productDisplayLabel(p: CatalogPresentation): string { + return `${p.productName} — ${p.displayName}`; + } + productColor(categoryName: string): string { - const colors = ['bg-blue-700','bg-violet-700','bg-emerald-700','bg-amber-700','bg-rose-700','bg-cyan-700','bg-indigo-700','bg-teal-700']; let hash = 0; for (let i = 0; i < categoryName.length; i++) hash = categoryName.charCodeAt(i) + ((hash << 5) - hash); - return colors[Math.abs(hash) % colors.length]; + return PRODUCT_COLORS[Math.abs(hash) % PRODUCT_COLORS.length]; } setPaymentMethod(m: 'cash' | 'card' | 'transfer' | 'credit' | 'delivery'): void { this.paymentMethod.set(m); } setCashTendered(v: number): void { this.cashTendered.set(v); } diff --git a/notification-service/package-lock.json b/notification-service/package-lock.json index db8d58e..933d29a 100644 --- a/notification-service/package-lock.json +++ b/notification-service/package-lock.json @@ -8,18 +8,18 @@ "name": "email-service", "version": "1.0.0", "dependencies": { - "bullmq": "^5.76.6", - "dotenv": "^16.5.0", - "express": "^4.21.2", + "bullmq": "^5.76.9", + "dotenv": "^17.4.2", + "express": "^5.2.1", "ioredis": "^5.10.1", - "nodemailer": "^6.10.1" + "nodemailer": "^8.0.7" }, "devDependencies": { "@types/express": "^5.0.3", - "@types/node": "^22.15.17", - "@types/nodemailer": "^6.4.17", + "@types/node": "^25.8.0", + "@types/nodemailer": "^8.0.0", "ts-node-dev": "^2.0.0", - "typescript": "^5.8.3" + "typescript": "^6.0.3" } }, "node_modules/@cspotcode/source-map-support": { @@ -229,19 +229,19 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.18.tgz", - "integrity": "sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==", + "version": "25.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", + "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/nodemailer": { - "version": "6.4.23", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.23.tgz", - "integrity": "sha512-aFV3/NsYFLSx9mbb5gtirBSXJnAlrusoKNuPbxsASWc7vrKLmIrTQRpdcxNcSFL3VW2A2XpeLEavwb2qMi6nlQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.0.tgz", + "integrity": "sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==", "dev": true, "license": "MIT", "dependencies": { @@ -298,13 +298,13 @@ "license": "MIT" }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" @@ -357,12 +357,6 @@ "dev": true, "license": "MIT" }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -384,42 +378,27 @@ } }, "node_modules/body-parser": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", - "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.15.1", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/brace-expansion": { @@ -454,16 +433,16 @@ "license": "MIT" }, "node_modules/bullmq": { - "version": "5.76.6", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.76.6.tgz", - "integrity": "sha512-vlmL3B3NVMRy6se3c7jPHn1Nhqxrg7+wlv1t3XAQFBYZNJDMLP0OO5x2AX5ca7DAuS1SU/C+VfYi+NHVoFK1QQ==", + "version": "5.76.9", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.76.9.tgz", + "integrity": "sha512-hJ7eq01XMcaN+jGZFq4ejIjyFdJo9fG+y/biI4DAY9Ltw/cv1/OSYBW0RSnNu2m8dMR5noc4+LotxcQp8+MVDA==", "license": "MIT", "dependencies": { "cron-parser": "4.9.0", "ioredis": "5.10.1", "msgpackr": "2.0.1", "node-abort-controller": "3.1.1", - "semver": "7.7.4", + "semver": "7.8.0", "tslib": "2.8.1" }, "engines": { @@ -550,15 +529,16 @@ "license": "MIT" }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -580,10 +560,13 @@ } }, "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/create-require": { "version": "1.1.1", @@ -605,12 +588,20 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/denque": { @@ -631,16 +622,6 @@ "node": ">= 0.8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -662,9 +643,9 @@ } }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -758,45 +739,42 @@ } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -817,21 +795,24 @@ } }, "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/forwarded": { @@ -844,12 +825,12 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/fs.realpath": { @@ -1012,15 +993,19 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/inflight": { @@ -1065,29 +1050,6 @@ "url": "https://opencollective.com/ioredis" } }, - "node_modules/ioredis/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/ioredis/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/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1159,6 +1121,12 @@ "node": ">=0.12.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -1197,63 +1165,49 @@ } }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" + "node": ">=18" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "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==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "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==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimatch": { @@ -1293,9 +1247,9 @@ } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "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/msgpackr": { @@ -1330,9 +1284,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -1360,9 +1314,9 @@ } }, "node_modules/nodemailer": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz", - "integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.7.tgz", + "integrity": "sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==", "license": "MIT-0", "engines": { "node": ">=6.0.0" @@ -1406,7 +1360,6 @@ "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" @@ -1439,10 +1392,14 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "license": "MIT" + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/picomatch": { "version": "2.3.2", @@ -1495,18 +1452,18 @@ } }, "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", + "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readdirp": { @@ -1579,25 +1536,21 @@ "rimraf": "bin.js" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -1606,9 +1559,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1618,48 +1571,48 @@ } }, "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/send/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/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { @@ -1940,22 +1893,40 @@ "license": "0BSD" }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1967,9 +1938,9 @@ } }, "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==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "dev": true, "license": "MIT" }, @@ -1982,15 +1953,6 @@ "node": ">= 0.8" } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -2011,7 +1973,6 @@ "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/xtend": { diff --git a/notification-service/package.json b/notification-service/package.json index 428b1a4..a5e0214 100644 --- a/notification-service/package.json +++ b/notification-service/package.json @@ -8,17 +8,17 @@ "start": "node dist/server.js" }, "dependencies": { - "bullmq": "^5.76.6", - "dotenv": "^16.5.0", - "express": "^4.21.2", + "bullmq": "^5.76.9", + "dotenv": "^17.4.2", + "express": "^5.2.1", "ioredis": "^5.10.1", - "nodemailer": "^6.10.1" + "nodemailer": "^8.0.7" }, "devDependencies": { "@types/express": "^5.0.3", - "@types/node": "^22.15.17", - "@types/nodemailer": "^6.4.17", + "@types/node": "^25.8.0", + "@types/nodemailer": "^8.0.0", "ts-node-dev": "^2.0.0", - "typescript": "^5.8.3" + "typescript": "^6.0.3" } } diff --git a/scripts/ai-dev-loop/LOOP_PROMPT.md b/scripts/ai-dev-loop/LOOP_PROMPT.md new file mode 100644 index 0000000..b3fe3e2 --- /dev/null +++ b/scripts/ai-dev-loop/LOOP_PROMPT.md @@ -0,0 +1,92 @@ +# TuColmadoRD — Autonomous AI Dev Loop + +You are running an autonomous development loop for TuColmadoRD, an Angular 19 + .NET 10 ERP/POS SaaS for colmados in the Dominican Republic. + +**Your job:** Run e2e tests, find failures, fix them, deploy, verify. Repeat until all tests pass. +**Never ask the user anything.** Make decisions independently. + +--- + +## Environment + +- Repo: `/home/fcastro_dev/dev_directories/projector_importantes_para_el_futuro/TuColmadoRD-Monorepo` +- Frontend: `frontend/web-admin/` (Angular 19) +- Backend API: `https://api.tucolmadord.com` (deployed on Hostinger) +- Production frontend (web-admin): `https://app.tucolmadord.com` +- Production landing: `https://tucolmadord.com` +- Git remote: `https://github.com/odimsom/TuColmadoRD-Monorepo.git` +- Deploy flow: push to `main` → GitHub Actions `cd-deploy.yml` → self-hosted runner on server deploys +- Test user: `test@tucolmadord.com` / `Test1234!` +- Server SSH: `root@177.7.48.169` (use sshpass or SSH key if available) + +--- + +## Each Iteration + +### Step 1 — Run Tests +```bash +cd /home/fcastro_dev/dev_directories/projector_importantes_para_el_futuro/TuColmadoRD-Monorepo +bash scripts/ai-dev-loop/run-tests.sh 2>&1 | tee scripts/ai-dev-loop/last-run.log +``` + +### Step 2 — Analyze Results +- Read `frontend/web-admin/e2e/results/test-results.json` +- Read screenshots for failed tests: `frontend/web-admin/e2e/results/*.png` +- Read screenshots VISUALLY (they are PNG images) to understand what the UI looked like when it failed +- Decide: is the failure in the **app code** or in the **test spec**? + - App bug → fix `frontend/web-admin/src/**` + - Test outdated → fix `frontend/web-admin/e2e/*.spec.ts` + - Missing feature → implement it in `src/` and add tests in `e2e/` + +### Step 3 — Fix +- Edit the relevant files +- If fixing a test selector, verify the HTML structure in the corresponding Angular component first +- Log what you did in `scripts/ai-dev-loop/LOOP_LOG.md` + +### Step 4 — Deploy (only if app code changed) +```bash +cd /home/fcastro_dev/dev_directories/projector_importantes_para_el_futuro/TuColmadoRD-Monorepo +git add -A +git commit -m "fix(e2e-loop): " +git push origin main +``` +Then wait for CI/CD to deploy (check every 60s for up to 10 minutes): +```bash +gh run list --branch main --limit 3 +gh run watch +``` + +### Step 5 — Verify on Server (if deploy issues suspected) +```bash +# Check server health after deploy +ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@177.7.48.169 "cd /app/tucolmadord && docker compose ps && docker compose logs --tail=20 2>&1 | tail -30" +``` +If services are down, restart them: +```bash +ssh -o StrictHostKeyChecking=no root@177.7.48.169 "cd /app/tucolmadord && docker compose up -d" +``` + +### Step 6 — Repeat +Go back to Step 1. + +--- + +## Stop Condition +Stop the loop when: +- All tests pass for **2 consecutive runs** with no changes needed +- OR you have been running for more than 4 hours +- OR you encounter an error you cannot fix (authentication error on server, CI/CD pipeline broken, etc.) + +When stopping, write a final summary in `scripts/ai-dev-loop/LOOP_LOG.md`. + +--- + +## Rules +1. **Never ask the user for input.** Make your best judgment call. +2. When in doubt about a fix, try the less invasive option first. +3. If a test fails because a feature doesn't exist yet in the UI, implement the feature first, then add/update the test. +4. Always look at screenshots to understand visual failures — `Read` the PNG files. +5. Keep commits small and descriptive. +6. If the server is unreachable, skip SSH steps and continue with local fixes. +7. Do not change the test user credentials or the production API URL. +8. Log every fix and result in `LOOP_LOG.md`. diff --git a/scripts/ai-dev-loop/run-tests.sh b/scripts/ai-dev-loop/run-tests.sh new file mode 100755 index 0000000..c9b9bbc --- /dev/null +++ b/scripts/ai-dev-loop/run-tests.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Runs e2e tests against production and outputs structured summary +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +FRONTEND="$REPO_ROOT/frontend/web-admin" +RESULTS="$FRONTEND/e2e/results" + +mkdir -p "$RESULTS" + +echo "=== TuColmadoRD AI Dev Loop - Test Run $(date '+%Y-%m-%d %H:%M:%S') ===" +echo "" + +cd "$FRONTEND" + +# Ensure playwright browsers are installed +npx playwright install chromium --with-deps 2>/dev/null || true + +# Run tests against production +echo "Running e2e tests against https://tucolmadord.com..." +EXIT_CODE=0 +npx playwright test --config=playwright.prod.config.ts --reporter=list,json 2>&1 || EXIT_CODE=$? + +echo "" +if [ $EXIT_CODE -eq 0 ]; then + echo "STATUS: ALL_PASS" +else + echo "STATUS: FAILURES_DETECTED" +fi + +# Print JSON summary if available +if [ -f "$RESULTS/test-results.json" ]; then + python3 -c " +import json, sys +data = json.load(open('$RESULTS/test-results.json')) +suites = data.get('suites', []) +failed = [] +passed = [] +for suite in suites: + for spec in suite.get('specs', []): + for test in spec.get('tests', []): + name = suite.get('title','') + ' > ' + spec.get('title','') + if test.get('status') == 'expected': + passed.append(name) + else: + failed.append(name + ' [' + str(test.get('results',[{}])[-1].get('error',{}).get('message','unknown error'))[:200] + ']') +print(f'PASSED: {len(passed)}') +print(f'FAILED: {len(failed)}') +for f in failed: + print(f' FAIL: {f}') +" +fi + +exit $EXIT_CODE diff --git a/scripts/package-lock.json b/scripts/package-lock.json index 02428c1..f45d87e 100644 --- a/scripts/package-lock.json +++ b/scripts/package-lock.json @@ -1,379 +1,379 @@ -{ - "name": "scripts", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "bcryptjs": "^3.0.3", - "mongoose": "^9.4.1", - "pg": "^8.20.0" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.8.tgz", - "integrity": "sha512-kpjr2jy2w71w0oqAMI8oibBmiF9lXxWkEQs5gMkW4hVE48bsqINGLxnCSYW62ck/NHXJQpQEfA9WlJ1sY0eqBg==", - "license": "MIT", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "license": "MIT" - }, - "node_modules/@types/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", - "license": "MIT", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/bcryptjs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", - "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", - "license": "BSD-3-Clause", - "bin": { - "bcrypt": "bin/bcrypt" - } - }, - "node_modules/bson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", - "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/kareem": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.2.0.tgz", - "integrity": "sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "license": "MIT" - }, - "node_modules/mongodb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.1.tgz", - "integrity": "sha512-067DXiMjcpYQl6bGjWQoTUEE9UoRViTtKFcoqX7z08I+iDZv/emH1g8XEFiO3qiDfXAheT5ozl1VffDTKhIW/w==", - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^7.1.1", - "mongodb-connection-string-url": "^7.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.806.0", - "@mongodb-js/zstd": "^7.0.0", - "gcp-metadata": "^7.0.1", - "kerberos": "^7.0.0", - "mongodb-client-encryption": ">=7.0.0 <7.1.0", - "snappy": "^7.3.2", - "socks": "^2.8.6" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", - "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^13.0.0", - "whatwg-url": "^14.1.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/mongoose": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.4.1.tgz", - "integrity": "sha512-4rFBWa+/wdBQSfvnOPJBpiSG6UCEbhSQh865dEdaH9Y8WfHBUC+I2XT28dp0IBIGrEwmh+gzrgZgea5PbmrHWA==", - "license": "MIT", - "dependencies": { - "kareem": "3.2.0", - "mongodb": "~7.1", - "mpath": "0.9.0", - "mquery": "6.0.0", - "ms": "2.1.3", - "sift": "17.1.3" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz", - "integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==", - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "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/pg": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", - "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.12.0", - "pg-pool": "^3.13.0", - "pg-protocol": "^1.13.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.3.0" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", - "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", - "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", - "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", - "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", - "license": "MIT" - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "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==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - } - } -} +{ + "name": "scripts", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "bcryptjs": "^3.0.3", + "mongoose": "^9.6.2", + "pg": "^8.20.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.11.tgz", + "integrity": "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "node_modules/bson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", + "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/kareem": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.3.0.tgz", + "integrity": "sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.2.0.tgz", + "integrity": "sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^7.2.0", + "mongodb-connection-string-url": "^7.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": ">=7.0.0 <7.1.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", + "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/mongoose": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.6.2.tgz", + "integrity": "sha512-7m8HntjkoRnwEmuPC0kdlwcZXJOQf4twumFj+PNzg/anqqZE2Er7hQslqyzy07mP3JcFjoTSgH5765PyqOXsxw==", + "license": "MIT", + "dependencies": { + "kareem": "3.3.0", + "mongodb": "~7.2", + "mpath": "0.9.0", + "mquery": "6.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz", + "integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==", + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "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/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "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==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/scripts/package.json b/scripts/package.json index c23ff71..e4a4416 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -1,7 +1,7 @@ { "dependencies": { "bcryptjs": "^3.0.3", - "mongoose": "^9.4.1", + "mongoose": "^9.6.2", "pg": "^8.20.0" } } diff --git a/services/catalog-service/Cargo.lock b/services/catalog-service/Cargo.lock index cbc18d1..a3e4982 100644 --- a/services/catalog-service/Cargo.lock +++ b/services/catalog-service/Cargo.lock @@ -47,6 +47,12 @@ dependencies = [ "rustversion", ] +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + [[package]] name = "async-compression" version = "0.4.42" @@ -60,14 +66,14 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.89" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "proc-macro2", - "quote", - "syn", + "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -93,14 +99,14 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.7.9" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ - "async-trait", "axum-core", "axum-macros", "bytes", + "form_urlencoded", "futures-util", "http", "http-body", @@ -113,14 +119,13 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", "sync_wrapper", "tokio", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", "tracing", @@ -128,19 +133,17 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -149,9 +152,9 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", @@ -228,10 +231,10 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror 1.0.69", + "thiserror 2.0.18", "tokio", "tokio-retry", - "tower 0.4.13", + "tower", "tower-http", "tracing", "tracing-subscriber", @@ -460,7 +463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -485,6 +488,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.4.1" @@ -539,21 +552,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.32" @@ -598,17 +596,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-sink" version = "0.3.32" @@ -627,10 +614,8 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -963,15 +948,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1077,9 +1053,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" @@ -1130,7 +1106,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1239,26 +1215,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pin-project" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1445,28 +1401,30 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "redis" -version = "0.27.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" +checksum = "72d32a1ac9123f0d84fda64bfc02a271d9868483162dd2d9099b5c362ece064c" dependencies = [ "arc-swap", - "async-trait", + "arcstr", + "async-lock", "backon", "bytes", + "cfg-if", "combine", - "futures", + "futures-channel", "futures-util", - "itertools", "itoa", "num-bigint", "percent-encoding", "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.5.10", + "socket2", "tokio", "tokio-util", "url", + "xxhash-rust", ] [[package]] @@ -1759,16 +1717,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -2133,7 +2081,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -2184,23 +2132,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.3" @@ -2212,6 +2143,7 @@ dependencies = [ "pin-project-lite", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -2219,9 +2151,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" dependencies = [ "async-compression", "bitflags", @@ -2229,7 +2161,6 @@ dependencies = [ "futures-core", "http", "http-body", - "http-body-util", "pin-project-lite", "tokio", "tokio-util", @@ -2871,6 +2802,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.2" diff --git a/services/catalog-service/Cargo.toml b/services/catalog-service/Cargo.toml index 21ae2b4..b8dba9e 100644 --- a/services/catalog-service/Cargo.toml +++ b/services/catalog-service/Cargo.toml @@ -8,19 +8,19 @@ name = "catalog-service" path = "src/main.rs" [dependencies] -axum = { version = "0.7", features = ["macros"] } +axum = { version = "0.8", features = ["macros"] } tokio = { version = "1", features = ["full"] } -tower = { version = "0.4", features = ["timeout", "limit", "util"] } -tower-http = { version = "0.5", features = ["trace", "cors", "compression-gzip"] } +tower = { version = "0.5", features = ["timeout", "limit", "util"] } +tower-http = { version = "0.6", features = ["trace", "cors", "compression-gzip"] } serde = { version = "1", features = ["derive"] } serde_json = "1" sqlx = { version = "0.8", features = ["postgres", "runtime-tokio-rustls", "uuid", "chrono"] } -redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] } +redis = { version = "1.2", features = ["tokio-comp", "connection-manager"] } prometheus = { version = "0.13", features = ["process"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } anyhow = "1" -thiserror = "1" +thiserror = "2" uuid = { version = "1", features = ["serde", "v4"] } chrono = { version = "0.4", features = ["serde"] } dotenvy = "0.15" diff --git a/services/reports-service/Cargo.lock b/services/reports-service/Cargo.lock index fb7462b..b4f6478 100644 --- a/services/reports-service/Cargo.lock +++ b/services/reports-service/Cargo.lock @@ -47,6 +47,12 @@ dependencies = [ "rustversion", ] +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + [[package]] name = "async-compression" version = "0.4.42" @@ -60,14 +66,14 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.89" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "proc-macro2", - "quote", - "syn", + "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -93,14 +99,14 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.7.9" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ - "async-trait", "axum-core", "axum-macros", "bytes", + "form_urlencoded", "futures-util", "http", "http-body", @@ -113,8 +119,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -128,19 +133,17 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -149,9 +152,9 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", @@ -442,6 +445,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.4.1" @@ -496,21 +509,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.32" @@ -555,17 +553,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-sink" version = "0.3.32" @@ -584,10 +571,8 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -919,15 +904,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1033,9 +1009,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" @@ -1273,22 +1249,21 @@ dependencies = [ [[package]] name = "procfs" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags", "hex", - "lazy_static", "procfs-core", "rustix", ] [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags", "hex", @@ -1296,9 +1271,9 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" +checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ "cfg-if", "fnv", @@ -1308,14 +1283,28 @@ dependencies = [ "parking_lot", "procfs", "protobuf", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "protobuf" -version = "2.28.0" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-support" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" +dependencies = [ + "thiserror 1.0.69", +] [[package]] name = "quote" @@ -1364,28 +1353,30 @@ dependencies = [ [[package]] name = "redis" -version = "0.27.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" +checksum = "72d32a1ac9123f0d84fda64bfc02a271d9868483162dd2d9099b5c362ece064c" dependencies = [ "arc-swap", - "async-trait", + "arcstr", + "async-lock", "backon", "bytes", + "cfg-if", "combine", - "futures", + "futures-channel", "futures-util", - "itertools", "itoa", "num-bigint", "percent-encoding", "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.5.10", + "socket2", "tokio", "tokio-util", "url", + "xxhash-rust", ] [[package]] @@ -1487,7 +1478,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1698,16 +1689,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -2072,7 +2053,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -2130,9 +2111,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" dependencies = [ "async-compression", "bitflags", @@ -2140,7 +2121,6 @@ dependencies = [ "futures-core", "http", "http-body", - "http-body-util", "pin-project-lite", "tokio", "tokio-util", @@ -2543,15 +2523,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -2782,6 +2753,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.2" diff --git a/services/reports-service/Cargo.toml b/services/reports-service/Cargo.toml index 8978ce8..d7b44b3 100644 --- a/services/reports-service/Cargo.toml +++ b/services/reports-service/Cargo.toml @@ -8,14 +8,14 @@ name = "reports-service" path = "src/main.rs" [dependencies] -axum = { version = "0.7", features = ["macros"] } +axum = { version = "0.8", features = ["macros"] } tokio = { version = "1", features = ["full"] } -tower-http = { version = "0.5", features = ["trace", "cors", "compression-gzip"] } +tower-http = { version = "0.6", features = ["trace", "cors", "compression-gzip"] } serde = { version = "1", features = ["derive"] } serde_json = "1" sqlx = { version = "0.8", features = ["postgres", "runtime-tokio-rustls", "uuid", "chrono"] } -redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] } -prometheus = { version = "0.13", features = ["process"] } +redis = { version = "1.2", features = ["tokio-comp", "connection-manager"] } +prometheus = { version = "0.14", features = ["process"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } anyhow = "1"