diff --git a/.env.example b/.env.example index df65e82ec..e48ea3faa 100644 --- a/.env.example +++ b/.env.example @@ -19,6 +19,11 @@ ACCESS_GROUP_SERVICE_HANDLER="" ACCESS_GROUPS_STATIC_ENABLED=true ACCESS_GROUPS_STATIC_VALUES="" ACCESS_GROUPS_OIDCPAYLOAD_ENABLED=true +ACCESS_GROUPS_REST_ENABLED=true +ACCESS_GROUPS_SERVICE_REST_AUTH_KEY="Authorization" +ACCESS_GROUPS_SERVICE_REST_AUTH_VALUE="" +ACCESS_GROUPS_SERVICE_REST_API_URL="" +ACCESS_GROUPS_SERVICE_REST_USER_ID_FIELD="" #field to take as userID from user payload DOI_PREFIX="" EXPRESS_SESSION_SECRET="" EXPRESS_SESSION_STORE="" @@ -33,6 +38,7 @@ LDAP_SEARCH_BASE= LDAP_SEARCH_FILTER="(LDAPUsername={{username}})" OIDC_ISSUER="" OIDC_CLIENT_ID="" +OIDC_ADDITIONAL_AUTHORIZED_PARTIES="client1, client2" OIDC_CLIENT_SECRET="" OIDC_CALLBACK_URL="" OIDC_SCOPE="" @@ -84,19 +90,17 @@ MS365_CLIENT_ID= MS365_CLIENT_SECRET= POLICY_PUBLICATION_SHIFT=3 years POLICY_RETENTION_SHIFT=-1 (indefinitely) -ELASTICSEARCH_ENABLED=<"yes"|"no"> -ES_HOST="https://localhost:9200" -ES_USERNAME="elastic" -ES_PASSWORD="duo-password" -ES_PORT=9200 -MONGODB_COLLECTION="Dataset" -ES_MAX_RESULT=100000 -ES_FIELDS_LIMIT=400000 -ES_INDEX="dataset" -ES_REFRESH=<"wait_for"|"false"> -STACK_VERSION="8.8.2" -CLUSTER_NAME="es-cluster" -MEM_LIMIT="4G" + +# "wait_for": waits for index refresh before returning, recommended for development and testing. +# "false": returns immediately without waiting, recommended for production. +OPENSEARCH_REFRESH=<"wait_for"|"false"> +OPENSEARCH_ENABLED=<"yes"|"no"> +OPENSEARCH_ENABLED="https://localhost:9200" +OPENSEARCH_ENABLED="admin" +OPENSEARCH_ENABLED="Scicat_default_password_2026" +OPENSEARCH_DEFAULT_INDEX="dataset" +OPENSEARCH_DATA_SYNC_BATCH_SIZE=50000 + FRONTEND_CONFIG_FILE="./src/config/frontend.config.json" FRONTEND_THEME_FILE="./src/config/frontend.theme.json" LOGGERS_CONFIG_FILE="loggers.json" diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index 9af29eedd..4204ec651 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -15,7 +15,7 @@ jobs: ## Extract information about the dependencies being updated by a Dependabot-generated PR - name: Dependabot metadata id: dependabot-metadata - uses: dependabot/fetch-metadata@v2.5.0 + uses: dependabot/fetch-metadata@v3.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5c04d6690..6bd471f7d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,15 +14,15 @@ jobs: uses: actions/checkout@v6 - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 with: platforms: arm64 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Login to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -30,21 +30,21 @@ jobs: - name: Create image tags id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ghcr.io/scicatproject/backend-next flavor: latest=true # adds :latest tag to outputs.tags tags: type=sha,format=long,prefix= # adds : tag to outputs.tags - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64/v8 push: true tags: ${{ steps.meta.outputs.tags }} - - uses: actions/create-github-app-token@v2 + - uses: actions/create-github-app-token@v3 id: app-token with: app-id: ${{ secrets.WORKFLOW_DISPATCHER_APP_ID }} diff --git a/.github/workflows/release-and-publish-sdk.yml b/.github/workflows/release-and-publish-sdk.yml index 9de500d47..943584614 100644 --- a/.github/workflows/release-and-publish-sdk.yml +++ b/.github/workflows/release-and-publish-sdk.yml @@ -50,13 +50,13 @@ jobs: ## The setup-qemu-action simplifies the setup of QEMU for cross-platform builds ## https://github.com/docker/setup-qemu-action - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -75,7 +75,7 @@ jobs: ## https://github.com/docker/metadata-action - name: Docker meta id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ghcr.io/scicatproject/backend-next tags: | @@ -85,14 +85,14 @@ jobs: type=raw,value={{date 'YYYY_MM'}},prefix=r_ - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64/v8 push: true tags: ${{ steps.meta.outputs.tags }} - - uses: actions/create-github-app-token@v2 + - uses: actions/create-github-app-token@v3 id: app-token with: app-id: ${{ secrets.WORKFLOW_DISPATCHER_APP_ID }} @@ -146,7 +146,7 @@ jobs: - name: Download the Swagger schema run: curl -o ./swagger-schema.json http://localhost:3000/explorer-json - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 with: name: swagger-schema-${{ github.sha }} path: ./swagger-schema.json @@ -164,7 +164,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 + - uses: actions/download-artifact@v8 with: name: swagger-schema-${{ github.sha }} path: . @@ -187,7 +187,7 @@ jobs: fi ) - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 with: name: sdk-${{ matrix.generator }}-${{ github.sha }} path: ./sdk @@ -213,7 +213,7 @@ jobs: registry-url: "https://registry.npmjs.org/" - name: Download TypeScript SDK Artifact - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: sdk-${{ matrix.sdk_type }}-${{ github.sha }} path: ./sdk @@ -253,7 +253,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} - name: Download Python SDK Artifact - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: sdk-${{ matrix.sdk_type }}-${{ github.sha }} path: ./sdk diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 33221bfdb..7f6bbe6de 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -103,14 +103,14 @@ jobs: run: npm run build api_tests: - name: API tests with ElasticSearch enabled - ${{ matrix.elasticsearch_enabled }} + name: API tests with OpenSearch enabled - ${{ matrix.opensearch_enabled }} needs: [install-and-cache] runs-on: ubuntu-latest strategy: fail-fast: false matrix: - elasticsearch_enabled: ["yes", "no"] + opensearch_enabled: ["yes", "no"] steps: - name: Checkout code @@ -130,13 +130,17 @@ jobs: - name: API tests env: - ELASTICSEARCH_ENABLED: ${{ matrix.elasticsearch_enabled }} - CLUSTER_NAME: es-cluster - ES_PASSWORD: duo-password - MEM_LIMIT: 4G - STACK_VERSION: 8.8.2 + COMPOSE_PROFILES: ${{ matrix.opensearch_enabled == 'yes' && 'opensearch' || ''}} + OPENSEARCH_ENABLED: ${{ matrix.opensearch_enabled }} + OIDC_ISSUER: http://localhost:8080/local-test + OIDC_CLIENT_ID: scicat-client-test + OIDC_CLIENT_SECRET: secret + OIDC_SCOPE: openid profile email + OIDC_ADDITIONAL_AUTHORIZED_PARTIES: additional-authorized-client-test-1, additional-authorized-client-test-2 + # Start mongo container and app before running api tests run: | + cp opensearchConfig.example.json opensearchConfig.json cp CI/ESS/docker-compose.api.yaml docker-compose.yaml - docker compose up --build -d - npm run test:api + docker compose up --build -d --wait + OPENSEARCH_ENABLED=${{ matrix.opensearch_enabled }} npm run test:api diff --git a/.github/workflows/upload-sdk-artifact.yml b/.github/workflows/upload-sdk-artifact.yml index 843cfd565..0feda6844 100644 --- a/.github/workflows/upload-sdk-artifact.yml +++ b/.github/workflows/upload-sdk-artifact.yml @@ -43,7 +43,7 @@ jobs: - name: Download the Swagger schema run: curl -o ./swagger-schema.json http://localhost:3000/explorer-json - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 with: name: swagger-schema-${{ github.sha }} path: ./swagger-schema.json @@ -60,7 +60,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 + - uses: actions/download-artifact@v8 with: name: swagger-schema-${{ github.sha }} path: . @@ -81,7 +81,7 @@ jobs: fi ) - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: github.event_name == 'push' with: name: sdk-${{ matrix.generator }}-${{ github.sha }} @@ -93,6 +93,6 @@ jobs: - generate-and-upload-sdk if: github.event_name != 'push' steps: - - uses: geekyeggo/delete-artifact@v5 + - uses: geekyeggo/delete-artifact@v6 with: name: swagger-* diff --git a/.gitignore b/.gitignore index 3adbab30e..13e09a0a3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ jobConfig.json jobConfig.yaml metricsConfig.json publishedDataConfig.json +openSearchConfig.json # Configs .env diff --git a/CI/E2E/.env.backend-next.example b/CI/E2E/.env.backend-next.example index 2d9a8d313..652ab6cc5 100644 --- a/CI/E2E/.env.backend-next.example +++ b/CI/E2E/.env.backend-next.example @@ -39,12 +39,9 @@ DATASET_CREATION_VALIDATION_REGEX="^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][ PROPOSAL_GROUPS="proposalingestor" SAMPLE_GROUPS="" -ELASTICSEARCH_ENABLED='yes' -ES_HOST=http://es01:9200 -ES_USERNAME=elastic -ES_PASSWORD=duo-password -MONGODB_COLLECTION=Dataset -ES_MAX_RESULT=210000 -ES_FIELDS_LIMIT=400000 -ES_INDEX="dataset" -ES_REFRESH="wait_for" \ No newline at end of file +OPENSEARCH_ENABLED='yes' +OPENSEARCH_DEFAULT_INDEX="dataset" +OPENSEARCH_HOST=https://localhost:9200 +OPENSEARCH_USERNAME=admin +OPENSEARCH_PASSWORD=Scicat_default_password_2026 +OPENSEARCH_REFRESH="wait_for" \ No newline at end of file diff --git a/CI/E2E/.env.elastic-search b/CI/E2E/.env.elastic-search deleted file mode 100644 index d51156aa8..000000000 --- a/CI/E2E/.env.elastic-search +++ /dev/null @@ -1,6 +0,0 @@ -STACK_VERSION=8.8.2 -ES_PORT=9200 -CLUSTER_NAME=es-cluster -MEM_LIMIT=4G -ES_USERNAME=elastic -ES_PASSWORD=duo-password \ No newline at end of file diff --git a/CI/E2E/backend.env b/CI/E2E/backend.env index c6166a164..f97fe1c0f 100644 --- a/CI/E2E/backend.env +++ b/CI/E2E/backend.env @@ -36,12 +36,9 @@ DATASET_CREATION_VALIDATION_REGEX="^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][ PROPOSAL_GROUPS="proposalingestor" SAMPLE_GROUPS="" -ELASTICSEARCH_ENABLED='yes' -ES_HOST=http://es01:9200 -ES_USERNAME=elastic -ES_PASSWORD=duo-password -MONGODB_COLLECTION=Dataset -ES_MAX_RESULT=210000 -ES_FIELDS_LIMIT=400000 -ES_INDEX="dataset" -ES_REFRESH="wait_for" +OPENSEARCH_ENABLED=yes +OPENSEARCH_DEFAULT_INDEX="dataset" +OPENSEARCH_HOST=https://localhost:9200 +OPENSEARCH_USERNAME=admin +OPENSEARCH_PASSWORD=Scicat_default_password_2026 +OPENSEARCH_REFRESH="wait_for" \ No newline at end of file diff --git a/CI/E2E/docker-compose-local-no-es.yaml b/CI/E2E/docker-compose-local-no-es.yaml deleted file mode 100644 index 473cd43e4..000000000 --- a/CI/E2E/docker-compose-local-no-es.yaml +++ /dev/null @@ -1,27 +0,0 @@ -version: "3.2" -services: - mongodb: - image: bitnami/mongodb:latest - volumes: - - "mongodb_data:/bitnami" - ports: - - "27017:27017" - scichat-loopback: - image: dacat/scichat-loopback:e2e - command: - [ - "./wait-for-it.sh", - "mongodb:27017", - "--", - "node", - "-r", - "dotenv/config", - "." - ] - volumes: - - ".env.scichat-loopback:/home/node/app/.env" - depends_on: - - mongodb -volumes: - mongodb_data: - driver: local diff --git a/CI/E2E/docker-compose-local.yaml b/CI/E2E/docker-compose-local.yaml index f4f7c8e82..e8ce2a091 100644 --- a/CI/E2E/docker-compose-local.yaml +++ b/CI/E2E/docker-compose-local.yaml @@ -1,11 +1,12 @@ version: "3.2" services: mongodb: - image: bitnami/mongodb:latest + image: mongo:latest volumes: - - "mongodb_data:/bitnami" + - "mongodb_data:/data/db" ports: - "27017:27017" + scichat-loopback: image: dacat/scichat-loopback:e2e command: @@ -23,28 +24,44 @@ services: depends_on: - mongodb - es01: + opensearch: depends_on: - mongodb - image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + image: opensearchproject/opensearch:3.5.0 ports: - - ${ES_PORT}:9200 + - 9200:9200 environment: - - node.name=es01 - - ES_JAVA_OPTS=-Xms2g -Xmx2g - - cluster.name=${CLUSTER_NAME} - - cluster.initial_master_nodes=es01 - - ELASTIC_PASSWORD=${ES_PASSWORD} + - node.name=opensearch + - discovery.type=single-node + - cluster.name=os-cluster - bootstrap.memory_lock=true - mem_limit: ${MEM_LIMIT} + - OPENSEARCH_JAVA_OPTS=-Xms2g -Xmx2g + - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Scicat_default_password_2026 + volumes: + - opensearch_data:/usr/share/opensearch/data + mem_limit: 4G ulimits: memlock: soft: -1 hard: -1 + + # Web UI for OpenSearch + # Enable this service if you want to use OpenSearch Dashboards to visualize and debug your OpenSearch data. + # Access it at http://localhost:5601 + # opensearch-dashboards: + # image: opensearchproject/opensearch-dashboards:3.5.0 + # ports: + # - "5601:5601" + # environment: + # - OPENSEARCH_HOSTS=https://opensearch:9200 + # - OPENSEARCH_USERNAME=admin + # - OPENSEARCH_PASSWORD=Scicat_default_password_2026 + # - OPENSEARCH_SSL_VERIFICATIONMODE=none + volumes: mongodb_data: driver: local - es01: + opensearch_data: driver: local diff --git a/CI/E2E/docker-compose.yaml b/CI/E2E/docker-compose.yaml index 9435844ef..f5d10923d 100644 --- a/CI/E2E/docker-compose.yaml +++ b/CI/E2E/docker-compose.yaml @@ -8,11 +8,11 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock mongodb: - image: "bitnami/mongodb:latest" + image: "mongo:latest" ports: - "27017:27017" volumes: - - "mongodb_data:/bitnami" + - "mongodb_data:/data/db" healthcheck: test: echo 'db.runCommand("ping").ok' | mongosh mongodb:27017/test --quiet interval: 10s @@ -63,35 +63,28 @@ services: - "traefik.http.routers.frontend.rule=PathPrefix(`/`)" - "traefik.http.routers.frontend.entrypoints=web" - es01: - image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2 + opensearch: + depends_on: + - mongodb + image: opensearchproject/opensearch:3.5.0 ports: - 9200:9200 environment: - - xpack.security.enabled=false - - node.name=es01 - - ES_JAVA_OPTS=-Xms512m -Xmx512m - - cluster.name=es-cluster - - cluster.initial_master_nodes=es01 + - node.name=opensearch + - discovery.type=single-node + - cluster.name=os-cluster - bootstrap.memory_lock=true - mem_limit: 1g + - OPENSEARCH_JAVA_OPTS=-Xms2g -Xmx2g + - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Scicat_default_password_2026 + volumes: + - opensearch_data:/usr/share/opensearch/data + mem_limit: 4G ulimits: memlock: soft: -1 hard: -1 - healthcheck: - test: - [ - "CMD-SHELL", - "curl -s -X GET 'http://es01:9200/_cluster/health?pretty' | grep status | grep -q '\\(green\\|yellow\\)'" - ] - interval: 30s - timeout: 10s - start_period: 60s - retries: 4 - volumes: mongodb_data: driver: local - es01: + opensearch_data: driver: local diff --git a/CI/ESS/docker-compose.api.yaml b/CI/ESS/docker-compose.api.yaml index c8c0d2e47..40a364e4c 100644 --- a/CI/ESS/docker-compose.api.yaml +++ b/CI/ESS/docker-compose.api.yaml @@ -1,30 +1,107 @@ services: + mock-oauth: + image: ghcr.io/navikt/mock-oauth2-server:latest + ports: + - "8080:8080" + environment: + SERVER_PORT: 8080 + JSON_CONFIG: | + { + "interactiveLogin": false, + "httpServer": "NettyWrapper", + "tokenCallbacks": [ + { + "issuerId": "local-test", + "tokenExpiry": 3600, + "requestMappings": [ + { + "requestParam": "client_id", + "match": "scicat-client-test", + "claims": { + "sub": "test-username", + "preferred_username": "test-username", + "email": "test@test.com", + "aud": "scicat-client-test", + "azp": "scicat-client-test" + } + }, + { + "requestParam": "client_id", + "match": "additional-authorized-client-test-1", + "claims": { + "sub": "test-username", + "preferred_username": "test-username", + "email": "test@test.com", + "aud": "scicat-client-test", + "azp": "additional-authorized-client-test-1" + } + }, + { + "requestParam": "client_id", + "match": "additional-authorized-client-test-2", + "claims": { + "sub": "test-username", + "preferred_username": "test-username", + "email": "test@test.com", + "aud": "scicat-client-test", + "azp": "additional-authorized-client-test-2" + } + }, + { + "requestParam": "client_id", + "match": "untrusted-client-test", + "claims": { + "sub": "test-username", + "preferred_username": "test-username", + "email": "test@test.com", + "aud": "untrusted-client-test", + "azp": "untrusted-client-test" + } + } + ] + } + ] + } + healthcheck: + test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/local-test/.well-known/openid-configuration"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 10s + mongodb: image: mongo:latest volumes: - - mongodb_data:/bitnami + - "mongodb_data:/data/db" ports: - "27017:27017" - es01: + opensearch: + profiles: + - opensearch depends_on: - mongodb - image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + image: opensearchproject/opensearch:3.5.0 ports: - "9200:9200" environment: - - node.name=es01 - - ES_JAVA_OPTS=-Xms2g -Xmx2g - - cluster.name=${CLUSTER_NAME} - - cluster.initial_master_nodes=es01 - - ELASTIC_PASSWORD=${ES_PASSWORD} + - node.name=opensearch + - discovery.type=single-node + - cluster.name=os-test-cluster - bootstrap.memory_lock=true - mem_limit: ${MEM_LIMIT} + - OPENSEARCH_JAVA_OPTS=-Xms2g -Xmx2g + - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Scicat_default_password_2026 + mem_limit: 4G ulimits: memlock: soft: -1 hard: -1 + healthcheck: + test: ["CMD-SHELL", "curl -sk -u admin:Scicat_default_password_2026 https://localhost:9200/_cluster/health || exit 1"] + interval: 10s + timeout: 10s + retries: 10 + start_period: 30s volumes: mongodb_data: driver: local - es01: - driver: local + diff --git a/CI/ESS/docker-compose.yaml b/CI/ESS/docker-compose.yaml index 2e8f9796f..b412a700f 100644 --- a/CI/ESS/docker-compose.yaml +++ b/CI/ESS/docker-compose.yaml @@ -27,22 +27,27 @@ services: depends_on: - mongodb - es01: + opensearch: depends_on: - mongodb - image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + image: opensearchproject/opensearch:3.5.0 + ports: + - 9200:9200 environment: - - node.name=es01 - - ES_JAVA_OPTS=-Xms2g -Xmx2g - - cluster.name=${CLUSTER_NAME} - - cluster.initial_master_nodes=es01 - - ELASTIC_PASSWORD=${ES_PASSWORD} + - node.name=opensearch + - discovery.type=single-node + - cluster.name=os-cluster - bootstrap.memory_lock=true - mem_limit: ${MEM_LIMIT} + - OPENSEARCH_JAVA_OPTS=-Xms2g -Xmx2g + - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Scicat_default_password_2026 + volumes: + - opensearch_data:/usr/share/opensearch/data + mem_limit: 4G ulimits: memlock: soft: -1 hard: -1 + # catanie: # build: # context: catanie @@ -114,5 +119,5 @@ volumes: driver: local rabbitmq_data: driver: local - es01: - driver: local + opensearch_data: + driver: local \ No newline at end of file diff --git a/README.md b/README.md index 7bfc22269..3ad25fd6c 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,8 @@ Valid environment variables for the .env file. See [.env.example](/.env.example) | `DOI_SHORT_SUFFIX` | string | | By default `uuidv4` is used to generate the DOI suffix but if this flag is `true` the shorter version of 10 random characters is used as DOI suffix. | | | `DOI_USERNAME` | string | | The facility DOI DataCite username. | | | `DOI_PASSWORD` | string | | The facility DOI DataCite password. | | +| `PUBLISHED_DATA_CONFIG_FILE` | string | | Path to the file containing the metadata and UI schemas for PublishedData. | `"publishedDataConfig.json"` | +| `AJV_CUSTOM_DEFINITIONS_FILE` | string | | The path to a JavaScript module that defines custom AJV keywords or dynamic defaults functions. | | | `EXPRESS_SESSION_SECRET` | string | No | Secret used to set up express session. Required if using OIDC authentication | | | `EXPRESS_SESSION_STORE` | string | Yes | Where to store the express session. When "mongo" on mongo else in memory | | | `HTTP_MAX_REDIRECTS` | number | Yes | Max redirects for HTTP requests. | 5 | @@ -187,6 +189,7 @@ Valid environment variables for the .env file. See [.env.example](/.env.example) | `LDAP_SEARCH_FILTER` | string | Yes | Search filter for your LDAP server. | | | `OIDC_ISSUER` | string | Yes | URL of the OIDC server providing the authentication service. Example: https://identity.esss.dk/realm/ess. | | | `OIDC_CLIENT_ID` | string | Yes | Identity of the client used to obtain the user token. Example: scicat. | | +| `OIDC_ADDITIONAL_AUTHORIZED_PARTIES` | string | No | Comma-separated list of additional OIDC client IDs allowed to present tokens to this backend. Used for token exchange scenarios where a third-party client obtains a token on behalf of a user. The client ID must appear as the `azp` claim in the token. Example: `additional-client1, additional-client2`. | | | `OIDC_CLIENT_SECRET` | string | Yes | Secret to provide to the OIDC service to obtain the user token. Example: Aa1JIw3kv3mQlGFWhRrE3gOdkH6xreAwro. | | | `OIDC_CALLBACK_URL` | string | Yes | SciCat callback URL to redirect to after a successful login. Example: http://myscicat/api/v3/oidc/callback. | | | `OIDC_SCOPE` | string | Yes | Space-separated list of info returned by the OIDC service. Example: "openid profile email". | | @@ -237,19 +240,13 @@ Valid environment variables for the .env file. See [.env.example](/.env.example) |`MS365_CLIENT_SECRET`| string | Yes | Client Secret for sending emails over Microsoft Graph API | | |`POLICY_PUBLICATION_SHIFT`| integer | Yes | Embargo period expressed in years. | 3 years | |`POLICY_RETENTION_SHIFT`| integer | Yes | Retention period (how long the facility will hold on to data) expressed in years. | -1 (indefinitely) | -|`ELASTICSEARCH_ENABLED`| string | | Flag to enable/disable the Elasticsearch endpoints. Values "yes" or "no". | "no" | -|`ES_HOST`| string | | Host of Elasticsearch server instance. |"https://localhost:9200"| -|`ES_USERNAME`| string | Yes | Elasticsearch username. | "elastic" | -|`ES_PASSWORD`| string | | Elasticsearch password. |"duo-password"| -|`ES_PORT`| number | | Elasticsearch port. |9200| -|`MONGODB_COLLECTION`| string | | Collection name to be mapped into specified Elasticsearch index. Used for data synchronization between MongoDB and Elasticsearch index. |"Dataset"| -|`ES_MAX_RESULT`| number | Yes | Maximum records that can be indexed into Elasticsearch. | 10000 | -|`ES_FIELDS_LIMIT`| number | Yes | The total number of fields in an index. | 1000 | -|`ES_INDEX`| string | | Setting default index for the application |"dataset"| -|`ES_REFRESH`| string | | If set to`wait_for`, Elasticsearch will wait till data is inserted into the specified index before returning a response. | false | -|`STACK_VERSION` | string | Yes | Defines the Elasticsearch version to deploy | "8.8.2" | -|`CLUSTER_NAME` | string | Yes | Sets the name of the Elasticsearch cluster | "es-cluster" | -|`MEM_LIMIT`| string | Yes | Specifies the max memory for Elasticsearch container (or process) | "4G" | +|`OPENSEARCH_ENABLED`| string | | Controls whether OpenSearch is enabled on application startup. If not provided or set to `no`, OpenSearch will not be instantiated.| "no" | +|`OPENSEARCH_DEFAULT_INDEX`| string | | Specifies the default index. If not provided, a default index named `dataset` will be created automatically. | "dataset" | +|`OPENSEARCH_HOST`| string | | Host of Opensearch server instance. | | +|`OPENSEARCH_USERNAME`| string | Yes | Username for OpenSearch authentication. Defaults to `admin` in standard deployments but can be configured to use a custom user with appropriate permissions. | "admin" | +|`OPENSEARCH_PASSWORD`| string | | Password used for OpenSearch authentication. Must match `OPENSEARCH_INITIAL_ADMIN_PASSWORD` used when creating the OpenSearch container. | | +|`OPENSEARCH_REFRESH`| string | | Controls index refresh behavior. `wait_for`waits for the next refresh cycle before returning, which is useful for development and testing.`false`skips waiting and is recommended for production. Defaults to false. | false | +|`OPENSEARCH_DATA_SYNC_BATCH_SIZE`| number | | Number of documents fetched from MongoDB per batch during OpenSearch data sync. | 1000 | |`FRONTEND_CONFIG_FILE`| string | | The file name for frontend configuration, located in the`/src/config`directory by default. | "./src/config/frontend.config.json" | |`FRONTEND_THEME_FILE`| string | | The file name for frontend theme, located in the`/src/config`directory by default. | "./src/config/frontend.theme.json" | |`LOGGERS_CONFIG_FILE`| string | | The file name for loggers configuration, located in the project root directory. | "loggers.json" | diff --git a/ajvCustomDefinitions.example.js b/ajvCustomDefinitions.example.js new file mode 100644 index 000000000..b97434bd6 --- /dev/null +++ b/ajvCustomDefinitions.example.js @@ -0,0 +1,41 @@ +keywords = [ + // Automatically sets the name property based on givenName and familyName + { + keyword: "setFullName", + schema: false, + modifying: true, + validate: function (data, dataCxt) { + data.name = + data.givenName && data.familyName + ? `${data.familyName}, ${data.givenName}` + : data.givenName || data.familyName || undefined; + return true; + }, + }, +]; + +// Computes the sum of all datasets size in DataCite format +async function computeTotalSize(ctx) { + const datasets = await ctx.datasetsService.findAll({ + where: { + $or: ctx.publishedData.datasetPids.map((p) => ({ + pid: p, + })), + }, + }); + + return () => { + if (!datasets) return; + + return [datasets.reduce((acc, ds) => acc + (ds.size ?? 0), 0).toString()]; + }; +} + +const dynamicDefaults = new Map([ + ["computeTotalSize", computeTotalSize], +]); + +module.exports = { + keywords, + dynamicDefaults, +}; diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index bf2d7cf96..dfdcb76ac 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -1,8 +1,8 @@ services: mongodb: - image: docker.io/bitnami/mongodb:4.2 + image: mongo:latest volumes: - - mongodb_data:/bitnami + - "mongodb_data:/data/db" backend: build: context: . diff --git a/docs/developer-guide/ajv-extensions.md b/docs/developer-guide/ajv-extensions.md new file mode 100644 index 000000000..e071649b0 --- /dev/null +++ b/docs/developer-guide/ajv-extensions.md @@ -0,0 +1,84 @@ +# Extending Ajv + +## Overview + +SciCat uses the [Ajv library](https://ajv.js.org/) to validate metadata for `PublishedData` objects against the configured JSON Schema. + +Ajv provides mechanisms to overcome some limitations of JSON Schema by allowing to register custom code to be run during the validation process. + +SciCat backend can load an external javascript module containing facility-specific code at runtime and execute it during validation. + +Supported features: +- registering new [keywords](https://ajv.js.org/keywords.html) +- registering new [dynamicDefaults functions](https://ajv.js.org/packages/ajv-keywords.html#dynamicdefaults) + +## Writing your own extensions + +Custom code will be loaded as a [Javascript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) by the backend. + +To load a module, define the `AJV_CUSTOM_DEFINITIONS_FILE` environment variable with the path to your module. + +It should export two symbols: +- `keywords` an array of custom keyword definitions +- `dynamicDefaults` a map of function name / function + +see [the example file](../../ajvCustomDefinitions.example.js). + +⚠️ Ajv expects higher-order functions (i.e., a function that returns another function). + +### Synchronous functions + +If a function is synchronous, it will simply be registered in ajv and its execution is entirely delegated to the library. + +Example: +```js +export const dynamicDefaults = new Map([ + ["mySyncDynamicDefault", () => () => Math.random()] +]); +``` + +### Asynchronous functions + +If you need to execute asynchronous code, you should declare your function `async` (only supported for dynamicDefaults). +It should return a synchronous function as ajv will not resolve any `Promise` returned by custom code. + +Asynchronous functions have access to additional context via the `ctx` argument: +- The `PublishedData` instance being validated +- Read-only access to the following services: `ProposalsService`, `DatasetsService` and `AttachmentsService` + +Currently only the following methods are supported on read-only services: +- `findOne` +- `findAll` +- `count` + +Example: +```js +export const dynamicDefaults = new Map([ + [ + "mergeKeywords", + async (ctx) => { + // Make async DB access + // This will be executed by the ValidatorService + const datasets = await ctx.datasetsService.findAll({ + where: { + $or: ctx.publishedData.datasetPids.map((p) => ({ + pid: p, + })), + }, + }); + + // Return a synchronous function processing data fetched from the DB + // This will be executed by ajv + return () => { + if (!datasets) return; + + const uniqueKeywords = new Set(datasets.flatMap((ds) => ds.keywords || [])); + return Array.from(uniqueKeywords).map((k) => ({ + subject: k, + lang: "en", + })); + }; + }, + ], +]); +``` diff --git a/docs/developer-guide/metadatakeys-module.md b/docs/developer-guide/metadatakeys-module.md new file mode 100644 index 000000000..f41dbe293 --- /dev/null +++ b/docs/developer-guide/metadatakeys-module.md @@ -0,0 +1,90 @@ +--- +title: MetadataKeys Synchronization Service Overview +audience: Technical +created_by: Junjie Quan +created_on: 2026-02-09 +--- + +## Overview & Problem Statement + +The Metadata Keys Module is a dedicated standalone component designed to manage and retrieve metadata keys across the platform. This module replaces the legacy GET /datasets/metadataKeys endpoint. + +### Problem Addressed + +The previous implementation in the Datasets service lacked a permission-based filtering layer. Because it attempted to return all global keys without ownership validation, it caused: + +- Performance: Significant latency when processing large datasets. +- Stability: Crashes occurred when retrieval limits were missing or improperly configured. +- Risks: Users could see metadata keys they did not have permissions to access. + +## Module Architecture + +This module consists of a dedicated Controller and Service layer that implements a robust permission-aware logic. + +### MetadataKeysController + +Provides the API interface for searching keys. Allowed filters can be found in `src/metadata-keys/metadatakeys.service.ts` and exmaple can be find in `src/metadata-keys/types/metadatakeys-filter-content.ts` + +- `Endpoint`: GET /metadatakeys (replaces /datasets/metadataKeys) +- `Method`: findAll +- `Endpoint Access`: Endpoint can be Accessed by any users + +### MetadataKeysService + +This handles the business logic and talks to the database. It is divided into user-facing search logic and internal data synchronization. + +#### Permission Layer (Applies to findAll only): + +When a user searches for keys, the service uses accessibleBy to automatically append access filters based on CASL permissions: + +- `Admins`: Can search and get all metadata keys in the system. +- `Authenticated Users`: Can only get keys where they are part of the ownerGroup or accessGroups. +- `Unauthenticated Users`: Can only get keys that are marked as isPublished. + +#### Service Methods: + +- `findAll`: The only public-facing method. It applies the permission layer and then uses a database aggregation pipeline to find and return the specific keys requested by the user. Every search is limited to 100 results by default, if limit is not provided. +- `insertManyFromSource`: An internal method that takes an original document (like a Dataset), extracts fields from **scientificMetadata**, **metadata**, and **customMetadata**, and creates new records in the Metadata Keys collection. +- `deleteMany`: Removes metadata key entries associated with a source document when that document is deleted from the system. +- `replaceManyFromSource`: Triggered when a source document (e.g., a Dataset or Proposal) is updated. It calls `deleteMany` and `insertManyFromSource` sequentially. + +## Usage Example + +To list all metadata keys associated with a dataset, the user must provide the sourceType and sourceId. If the fields array is provided, only those specific fields will be returned: + +```json +{ + "where": { + "sourceType": "dataset", + "sourceId": "datasetId" + }, + "fields": ["humanreadableName", "key"], + "limits": { + "limit": 10, + "skip": 0, + "sort": { + "createdAt": "asc | desc" + } + } +} +``` + +To retrieve a specific metadata key, use the following filter: + +```json +{ + "where": { + "sourceType": "dataset", + "sourceId": "datasetId", + "key": "metadata_key_name" + }, + "fields": ["key"], + "limits": { + "limit": 10, + "skip": 0, + "sort": { + "createdAt": "asc | desc" + } + } +} +``` diff --git a/docs/developer-guide/opensearch-guidelines.md b/docs/developer-guide/opensearch-guidelines.md new file mode 100644 index 000000000..8a26aeccb --- /dev/null +++ b/docs/developer-guide/opensearch-guidelines.md @@ -0,0 +1,174 @@ +--- +title: OpenSearch Integration +audience: Technical +created_by: Junjie Quan +created_on: 2026-03-17 +--- + +# OpenSearch Integration + +## Overview + +SciCat now includes an OpenSearch integration to support search functionality within the platform. The transition from Elasticsearch to OpenSearch was made following the Elasticsearch license change in order to maintain the use of fully open-source components in the project. + +The current OpenSearch integration supports partial text search for datasets. + +Text search currently targets only the following fields: + +- `datasetName` +- `description` + +All other filters and queries continue to be executed using MongoDB queries. + +SciCat uses the official OpenSearch JavaScript client `@opensearch-project/opensearch@^3.5.1` for indexing, synchronization, and search operations. This version is compatible with OpenSearch v3.5.0. + +To be able to start application with OpenSearch you will need to: + +## Getting Started + +To start the application with OpenSearch: + +1. Run `npm run prepare:local` to start the OpenSearch cluster as a Docker container. +2. Set `OPENSEARCH_ENABLED=yes` and provide values for all required environment variables: `OPENSEARCH_HOST`, `OPENSEARCH_USERNAME`, and `OPENSEARCH_PASSWORD`. + > **Note:** `OPENSEARCH_PASSWORD` must match `OPENSEARCH_INITIAL_ADMIN_PASSWORD` set when creating the OpenSearch container. +3. Start the application with `npm run start`. On successful connection you will see: + +``` + [Nest] 80126 - 03/17/2026, 3:09:41 PM LOG [Opensearch] Opensearch Connected +``` + +4. Open the Swagger page at `http://localhost:3000/explorer` and authorize with an `admin` token. +5. Execute `POST /opensearch/create-index` to create the index. + > **Note:** This step can be skipped if you want to use the default index `dataset`. +6. Execute `POST /opensearch/sync-database` to sync data from MongoDB into OpenSearch. On success you will see: + +```json +{ + "total": 21670, + "failed": 0, + "retry": 0, + "successful": 21670, + "noop": 0, + "time": 4777, + "bytes": 279159021, + "aborted": false +} +``` + +## Environment Configuration + +OpenSearch behavior is controlled using environment variables. +To enable OpenSearch, set `OPENSEARCH_ENABLED=yes` and provide values for all required environment variables: `OPENSEARCH_HOST`, `OPENSEARCH_USERNAME`, and `OPENSEARCH_PASSWORD`. + +| Variable | Example | Description | Required | +| --------------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| `OPENSEARCH_ENABLED` | `"yes" \| "no"` | Controls whether OpenSearch is enabled on application startup. If not provided or set to `no`, OpenSearch will not be instantiated. | Yes | +| `OPENSEARCH_DEFAULT_INDEX` | `dataset` | Specifies the default index. If not provided, a default index named `dataset` will be created automatically. | No | +| `OPENSEARCH_HOST` | `https://localhost:9200` | Specifies the OpenSearch server endpoint. | Yes | +| `OPENSEARCH_USERNAME` | `"admin"` | Username for OpenSearch authentication. Defaults to `admin` in standard deployments but can be configured to use a custom user with appropriate permissions. | Yes | +| `OPENSEARCH_PASSWORD` | `Scicat-password2026` | Password used for OpenSearch authentication. Must match `OPENSEARCH_INITIAL_ADMIN_PASSWORD` used when creating the OpenSearch container. | Yes | +| `OPENSEARCH_REFRESH` | `"wait_for" \| "false"` | Controls index refresh behavior. `wait_for` waits for the next refresh cycle before returning, which is useful for development and testing. `false` skips waiting and is recommended for production. Defaults to false. | No | +| `OPENSEARCH_DATA_SYNC_BATCH_SIZE` | 1000 | Number of documents fetched from MongoDB per batch during OpenSearch data sync. Defaults to 10000 | No | + +## Index Configuration + +OpenSearch index settings and mappings can be customized using a configuration file. + +An optional `opensearchConfig.json` file can be mounted to `/home/node/app/opensearchConfig.json` in the container (or placed in the project root when running locally) to define custom index settings and mappings. + +If not provided, a default configuration will be loaded from `opensearchConfig.example.json` in the root, supporting partial text search on `datasetName` and `description`. + +For full configuration options, see: +https://docs.opensearch.org/latest/install-and-configure/configuring-opensearch/index/ + +## Query Logic + +Search queries follow the process below. + +### Access Filtering + +Before performing text search, results are filtered based on user access permissions: + +1. If the user belongs to one or more `userGroups`, these are applied as access filters. +2. If the user has no groups and is not an admin, the `isPublished` filter is applied. +3. Admin users bypass group-based access filters, which means queries are executed against a larger dataset. This is a known limitation and may result in slower response times for admin search requests. + +### Text Search + +After access filtering, OpenSearch performs a partial text search on the following fields: + +- `datasetName` +- `description` + +These fields are currently hardcoded in the `MustFields` enum (`src/opensearch/providers/fields.enum.ts`) and are not configurable. + +## API Endpoints + +All OpenSearch endpoints are restricted to admin users. + +### Create Index + +**POST** `/opensearch/create-index` + +- `index` (body, required): Target index name. default: `dataset` +- `settings` (body, optional): Index settings to apply. If not provided, defaults from `opensearchConfig.json` are used. + +--- + +### Sync Database + +**POST** `/opensearch/sync-database` + +Synchronizes datasets from MongoDB to OpenSearch. + +- `index` (query, optional): Index name. default: `dataset` + +--- + +### Search + +**POST** `/opensearch/search` + +Performs partial text search on datasets. + +- `textQuery` (query): Search text (applies to `datasetName` and `description`) +- `index` (query, optional): Target index name. default: `dataset` +- `limit` (query, optional): Max results +- `skip` (query, optional): Offset + +Returns matching dataset `_id`s. + +--- + +### Delete Index + +**POST** `/opensearch/delete-index` + +Deletes an index. + +- `index` (query): Target index name. + +--- + +### Get Index Configuration + +**GET** `/opensearch/get-index` + +Retrieves index settings and mappings. + +- `index` (query): Target index name. default: `dataset` + +--- + +### Update Index Settings + +**POST** `/opensearch/update-index` + +Updates index settings. Closes the index, applies the new settings, then reopens it. + +- `index` (body, required): Target index name. default: `dataset` +- `settings` (body, optional): Index settings to apply. If not provided, defaults from `opensearchConfig.json` are used. + +--- + +If you encounter performance issues related to OpenSearch, please open a [GitHub issue](https://github.com/SciCatProject/backend/issues) or report them at the SciCat meeting. diff --git a/docs/frontend-config-guide/default-list-settings.md b/docs/frontend-config-guide/default-list-settings.md index f84d19e21..f3f57c043 100644 --- a/docs/frontend-config-guide/default-list-settings.md +++ b/docs/frontend-config-guide/default-list-settings.md @@ -21,7 +21,7 @@ Defines how each field is displayed in the list table. | `width` | `number` | Default width of the column. | `200` | | `format` | `string` | Optional property used **only** when `type` is set to `date`. Defines how ISO date strings are displayed (e.g. `yyyy-MM-dd`).
it fallsback to `dateFormat` or `yyyy-MM-dd HH:mm` for dataset and `yyyy-MM-dd` for proposal | `"yyyy-MM-dd"` | | `enabled` | `boolean` | Whether the column is displayed by default. | `true` | - +| `sort` | `string` | Optional property to define the default sort direction for a specific column. Accepts `"asc"` or `"desc"`.
**Note:** Only one column in the `defaultProposalsListSettings` or `defaultDatasetsListSettings` should have this property defined. If not specified anywhere, the table defaults to sorting by the `createdAt` column in descending order. | `"desc"` | --- ### **Filters** diff --git a/docs/frontend-config-guide/frontend-config.md b/docs/frontend-config-guide/frontend-config.md new file mode 100644 index 000000000..a0ece39fb --- /dev/null +++ b/docs/frontend-config-guide/frontend-config.md @@ -0,0 +1,99 @@ +# Frontend Configuration Guide + +## Overview + +This guide documents frontend configuration options that control various UI behaviors and features in SciCat. These settings are defined in the configuration file specified by the `FRONTEND_CONFIG_FILE` environment variable (default `src/config/frontend.config.json`). + +## Configuration Options + +| **Configuration Options** | **Type** | **Default Value** | **Description** | +| --------------------------------------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **`defaultMainPage`** | object | | Defines the default landing page for authenticated and non-authenticated users. | +|     `nonAuthenticatedUser` | string | `"DATASETS"` | Default landing page for non-authenticated users. | +|     `authenticatedUser` | string | `"PROPOSALS"` | Default landing page for authenticated users. | +| `statusBannerMessage` | string | `""` | Message displayed in the dismissible status banner. If not provided, the banner will not be shown. | +| `statusBannerCode` | string | `INFO` | Defines the statusBanner style. Supported values: `INFO` or `WARN`. Defaults to `INFO` if not provided. | +| `checkBoxFilterClickTrigger` | boolean | `false` | Enable/disable automatic filter application when clicking checkboxes in filters. | +| `accessTokenPrefix` | string | `"Bearer "` | Set the backend token prefix. Should be empty string for old backend or "Bearer " if using scicat-backend-next. | +| `addDatasetEnabled` | boolean | `false` | Show/hide the "Create Dataset" button in the Datasets Dashboard. | +| `archiveWorkflowEnabled` | boolean | `false` | Enable/disable the archive/retrieve workflow. | +| `datasetReduceEnabled` | boolean | `true` | Show/hide the "Reduce" tab. | +| `datasetJsonScientificMetadata` | boolean | `true` | Show/hide the "Scientific Metadata (JSON)" tab. | +| `editDatasetEnabled` | boolean | `true` | Show/hide the "Edit" buttons in the Datasets Details page | +| `editDatasetSampleEnabled` | boolean | `true` | **Deprecated** Enable/disable editing of which Sample a Dataset belongs to. | +| `editMetadataEnabled` | boolean | `true` | Enable/disable editing of Scientific Metadata. | +| `addSampleEnabled` | boolean | `false` | Show/hide the "Create Sample" button in the Sample Dashboard | +| `externalAuthEndpoint` | string | `"/api/v3/auth/msad"` | Endpoint used for third party authentication, e.g., LDAP. | +| `facility` | string | `"SciCat Vanilla"` | Facility running the SciCat instance. | +| `siteIcon` | string | `""` | **Deprecated** Path to the site icon/logo image file. | +| `siteTitle` | string | `""` | Title displayed in the header. | +| `siteSciCatLogo` | string | `""` | **Deprecated** Set to `"icon"` for icon-only display; full logo shown otherwise. | +| `loginFacilityLabel` | string | `""` | Label for the facility login option. | +| `loginLdapLabel` | string | `""` | Label for the LDAP login option. | +| `loginLocalLabel` | string | `""` | Label for the local login option. | +| `loginFacilityEnabled` | boolean | `true` | Enable/disable facility login option. | +| `loginLdapEnabled` | boolean | `true` | Enable/disable LDAP login option. | +| `loginLocalEnabled` | boolean | `true` | **Deprecated** Enable/disable local login option. | +| `fileColorEnabled` | boolean | `true` | **Deprecated** Enable/disable file size color representation in the Datasets Dashboard. | +| `fileDownloadEnabled` | boolean | `true` | Enable/disable download workflow for Dataset datafiles. | +| `gettingStarted` | string | `null` | URL to Getting Started guide for SciCat, displayed on the Help page. | +| `ingestManual` | string | `null` | URL to Ingest Manual for SciCat, displayed on the Help page. | +| `jobsEnabled` | boolean | `true` | Enable/disable Job workflow. | +| `jsonMetadataEnabled` | boolean | `true` | Show/hide the "Show Metadata" button on the details pages, allowing users to see the JSON representation of the current document. | +| `jupyterHubUrl` | string | `""` | URL to Jupyter Hub instance used for data analysis. | +| `landingPage` | string | `""` | URL to the facility's Landing Page for Published Data. | +| `lbBaseURL` | string | `""` | URL to the SciCat Backend. | +| `logbookEnabled` | boolean | `true` | Enable/disable SciChat Logbook integration. | +| `loginFormEnabled` | boolean | `true` | Enable/disable the local Login form. Should be disabled if using oAuth2 for authentication. | +| `metadataPreviewEnabled` | boolean | `true` | Enable/disable Scientific Metadata preview on the Datasets Dashboard. | +| `metadataStructure` | string | `""` | Allow tree structure for Scientific Metadata. Set to empty string for flat structure, or "tree" for tree structure. | +| `multipleDownloadAction` | string | `""` | URL to service handling direct download of datafiles. | +| `multipleDownloadEnabled` | boolean | `true` | Enable/disable ability to download multiple datafiles. | +| `oAuth2Endpoints` | array | `[]` | List of endpoints used for oAuth2 authentication. Each endpoint should have `authURL` and `displayText` properties. | +| `policiesEnabled` | boolean | `true` | Enable/disable Dataset Policies workflow. | +| `retrieveDestinations` | array | `[]` | List of destinations for Dataset retrievals. | +| `riotBaseUrl` | string | `""` | URL to SciChat client. | +| `scienceSearchEnabled` | boolean | `true` | Enable/disable filtering documents on Scientific Metadata. | +| `scienceSearchUnitsEnabled` | boolean | `true` | Enable/disable filtering documents on Scientific Metadata using units. | +| `searchPublicDataEnabled` | boolean | `true` | **Deprecated** Enable/disable filtering Datasets on public or non-public data. | +| `searchSamples` | boolean | `true` | Enable/disable searching Samples on Samples Dashboard. | +| `sftpHost` | string | `""` | URL to SFTP service used for downloading files exceeding maximum allowed file size. | +| `sourceFolder` | string | `""` | Default source folder path for datasets. | +| `maxDirectDownloadSize` | number | `0` | Set a maximum allowed file size for downloading datafiles over HTTP (in bytes). | +| `maxFileSizeWarning` | string | `""` | Warning message displayed when files exceed the maximum direct download size. Supports placeholders: ``, ``, ``. | +| `shareEnabled` | boolean | `true` | Enable/disable workflow for sharing Datasets with other users using their email address. | +| `shoppingCartEnabled` | boolean | `true` | Enable/disable the Dataset cart used for bulk actions. | +| `shoppingCartOnHeader` | boolean | `true` | Toggle Dataset cart placement, either on header or to the left on the Datasets Dashboard. | +| `tableSciDataEnabled` | boolean | `true` | Enable/disable Scientific Metadata table view on details pages. If disabled, Scientific Metadata is displayed as raw JSON. | +| `datasetDetailsShowMissingProposalId` | boolean | `false` | Show/hide the ProposalId property even when the proposal no longer exists | +| `notificationInterceptorEnabled` | boolean | `true` | Enable/disable a snackbar when creating, updating or deleting entities | +| `metadataEditingUnitListDisabled` | boolean | `true` | Enable/disable the unitlist dropdown in metadata edit view | +| `hideEmptyMetadataTable` | boolean | `false` | Show/hide metadata tables when it is empty | +| `datafilesActionsEnabled` | boolean | `true` | Enable/disable custom datafile actions configuration. | +| `datafilesActions` | array | `[]` | Array of custom action configurations for datafiles. Each action can define download, notebook generation, or other custom behaviors. | +| `defaultDatasetsListSettings` | object | `{}` | Configuration for datasets list columns, filters, and conditions. **Detailed documentation:** [Default List Settings Configuration](./default-list-settings.md) | +| `defaultProposalsListSettings` | object | `{}` | Configuration for proposals list columns and filters. **Detailed documentation:** [Default List Settings Configuration](./default-list-settings.md) | +| `labelsLocalization` | object | `{}` | Localization configuration for labels in datasets and proposals. Maps field names to display labels. | +| `dateFormat` | string | `"yyyy-MM-dd HH:mm"` | Default date format used throughout the application. | +| `datasetDetailComponent` | object | `{}` | Configuration for customizing the dataset detail page layout and components. **Detailed documentation:** [Dynamic Dataset Detail Component Configuration](./dynamic-dataset-detail-component.md) | +| **`mainMenu`** | object | | Configuration for main menu visibility based on user authentication status. | +|     **`nonAuthenticatedUser`** | object | | Menu configuration for non-authenticated users. | +|         `datasets` | boolean | `true` | Show/hide datasets menu item. | +|         `files` | boolean | `false` | Show/hide files menu item. | +|         `instruments` | boolean | `true` | Show/hide instruments menu item. | +|         `jobs` | boolean | `false` | Show/hide jobs menu item. | +|         `policies` | boolean | `false` | Show/hide policies menu item. | +|         `proposals` | boolean | `true` | Show/hide proposals menu item. | +|         `publishedData` | boolean | `true` | Show/hide published data menu item. | +|         `samples` | boolean | `false` | Show/hide samples menu item. | +|     **`authenticatedUser`** | object | | Menu configuration for authenticated users. | +|         `datasets` | boolean | `true` | Show/hide datasets menu item. | +|         `files` | boolean | `true` | Show/hide files menu item. | +|         `instruments` | boolean | `true` | Show/hide instruments menu item. | +|         `jobs` | boolean | `true` | Show/hide jobs menu item. | +|         `policies` | boolean | `false` | Show/hide policies menu item. | +|         `proposals` | boolean | `true` | Show/hide proposals menu item. | +|         `publishedData` | boolean | `true` | Show/hide published data menu item. | +|         `samples` | boolean | `true` | Show/hide samples menu item. | +| **`defaultTab`** | object | | Specifies which tab is shown by default when viewing different entities. | +|     `proposal` | string | `"details"` | Default tab for proposals. Valid values: `"details"`, `"datasets"`, `"relatedProposals"`, `"logbook"`. | diff --git a/docs/index.md b/docs/index.md index 6946b0615..22e9632ac 100644 --- a/docs/index.md +++ b/docs/index.md @@ -131,7 +131,7 @@ Valid environment variables for the .env file. See [.env.example](/.env.example) | `JWT_SECRET` | string | | The secret for your JWT token, used for authorization. | | | `JWT_EXPIRES_IN` | number | Yes | How long, in seconds, the JWT token is valid. | 3600 | | `LDAP_URL` | string | Yes | The URL to your LDAP server. | | -| `LDAP_BIND_DN` | string | Yes | Bind_DN for your LDAP server. | | +| `LDAP_BIND_DN` | string | Yes | Bind*DN for your LDAP server. | | | `LDAP_BIND_CREDENTIALS` | string | Yes | Credentials for your LDAP server. | | | `LDAP_SEARCH_BASE` | string | Yes | Search base for your LDAP server. | | | `LDAP_SEARCH_FILTER` | string | Yes | Search filter for your LDAP server. | | @@ -142,59 +142,57 @@ Valid environment variables for the .env file. See [.env.example](/.env.example) | `OIDC_SCOPE` | string | Yes | Space-separated list of info returned by the OIDC service. Example: "openid profile email". | | | `OIDC_SUCCESS_URL` | string | Yes | SciCat Frontend auth-callback URL. Required to pass user credentials to SciCat Frontend after OIDC login. Example: https://myscicatfrontend/auth-callback. Must be `frontend-base-url/auth-callback` or `frontend-base-url/login` for the official SciCat frontend. | | | `OIDC_RETURN_URL` | string | Yes | The path segment within the SciCat Frontend to redirect to, passed as query param in `OIDC_SUCCESS_URL` and handled by frontend. Example: /datasets. | | -| `OIDC_FRONTEND_CLIENTS` | string | Yes | Comma separated list of additional frontend OIDC clients for this backend. Example: scilog,maxiv. Their success and return URLs can be configured by setting `OIDC_${CLIENT}_SUCCESS_URL` (E.g. `OIDC_SCILOG_SUCCESS_URL`) and `OIDC_${CLIENT}_RETURN_URL` | | -| `OIDC_ACCESS_GROUPS` | string | Yes | Functionality is still unclear. | | -| `OIDC_ACCESS_GROUPS_PROPERTY` | string | Yes | Target field to get the access groups value from OIDC response. | | -| `OIDC_USERINFO_MAPPING_FIELD_USERNAME` | string | Yes | Comma-separated list of fields from the OIDC response to use as the user's profile username. Example: `OIDC_USERINFO_MAPPING_FIELD_USERNAME="iss, sub"`. | "preferred_username" \|\| "name" | -| `OIDC_USERINFO_MAPPING_FIELD_DISPLAYNAME` | string | Yes | Field from the OIDC response to use as the user's profile display name. Example: `OIDC_USERINFO_MAPPING_FIELD_DISPLAYNAME="preferred_username"`. | "name" | -| `OIDC_USERINFO_MAPPING_FIELD_EMAIL` | string | Yes | Field from the OIDC response to use as the user's profile email. | "email" | -| `OIDC_USERINFO_MAPPING_FIELD_FAMILYNAME` | string | Yes | Field from the OIDC response to use as the user's profile family name. | "family_name" | -| `OIDC_USERINFO_MAPPING_FIELD_ID` | string | Yes | Field from the OIDC response to use as the user's profile ID. | "sub" \|\| "user_id" | -| `OIDC_USERINFO_MAPPING_FIELD_THUMBNAILPHOTO`| string | Yes | Field from the OIDC response to use as the user's profile thumbnail photo. | "thumbnailPhoto" | -| `OIDC_USERINFO_MAPPING_FIELD_PROVIDER` | string | Yes | Field from the OIDC response to use as the user's profile provider. | "iss" | -| `OIDC_USERINFO_MAPPING_FIELD_GROUP` | string | Yes | Field from the OIDC response to use as the user's profile group. | "groups" | -| `OIDC_USERQUERY_OPERATOR` | string | Yes | Specifies the operator ("or" or "and") for UserModel.findOne queries, determining the logic used to match fields like "username" or "email". Example: `UserModel.findOne({$or: {"username":"testUser", "email":"test@test.com"}})`. | "or" | -| `OIDC_USERQUERY_FILTER` | string | Yes | Defines key-value pairs for UserModel.findOne queries, using a "key:value" format. Example: `OIDC_USERQUERY_FILTER="username:sub, email:email"`. | "username:username, email:email" | -| `LOGBOOK_ENABLED` | string | Yes | Flag to enable/disable the Logbook endpoints. Values "yes" or "no". | "no" | -| `LOGBOOK_BASE_URL` | string | Yes | The base URL to the Logbook API. Only required if Logbook is enabled. | | -| `METADATA_KEYS_RETURN_LIMIT` | number | Yes | The return limit for the `/Datasets/metadataKeys` endpoint. | | -| `METADATA_PARENT_INSTANCES_RETURN_LIMIT` | number | Yes | The return limit of Datasets to extract metadata keys from for the `/Datasets/metadataKeys` endpoint. | | -| `MONGODB_URI` | string | | The URI for your MongoDB instance. | | -| `OAI_PROVIDER_ROUTE` | string | Yes | URI to OAI provider, used for the `/publisheddata/:id/resync` endpoint. | | -| `PID_PREFIX` | string | | The facility PID prefix, with trailing slash. | | -| `PUBLIC_URL_PREFIX` | string | | The base URL to the facility Landing Page. | | -| `PORT` | number | Yes | The port on which you want to access the app. | 3000 | -| `RABBITMQ_ENABLED` | string | Yes | Flag to enable/disable RabbitMQ consumer. Values "yes" or "no". | "no" | -| `RABBITMQ_HOSTNAME` | string | Yes | The hostname of the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | -| `RABBITMQ_USERNAME` | string | Yes | The username used to authenticate to the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | -| `RABBITMQ_PASSWORD` | string | Yes | The password used to authenticate to the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | -| `REGISTER_DOI_URI` | string | | URI to the organization that registers the facility's DOIs. | | -| `REGISTER_METADATA_URI` | string | | URI to the organization that registers the facility's published data metadata. | | -| `SITE` | string | | The name of your site. | | -| `EMAIL_TYPE` | string | Yes | The type of your email provider. Options are "smtp" or "ms365". | "smtp" | -| `EMAIL_FROM` | string | Yes | Email address that emails should be sent from. | | -| `EMAIL_REPLYTO` | string | Yes | Email 'Reply-To' field. | | -| `SMTP_HOST` | string | Yes | Host of SMTP server. | | -| `SMTP_MESSAGE_FROM` | string | Yes | (Deprecated) Alternate spelling of EMAIL_FROM.| | -| `SMTP_PORT` | number | Yes | Port of SMTP server. | 587 | -| `SMTP_SECURE` | bool | Yes | Use encrypted SMTPS. | "no" | -| `MS365_TENANT_ID` | string | Yes | Tenant ID for sending emails over Microsoft Graph API. | | -| `MS365_CLIENT_ID` | string | Yes | Client ID for sending emails over Microsoft Graph API | | -| `MS365_CLIENT_SECRET` | string | Yes | Client Secret for sending emails over Microsoft Graph API | | -| `POLICY_PUBLICATION_SHIFT` | integer | Yes | Embargo period expressed in years. | 3 years | -| `POLICY_RETENTION_SHIFT` | integer | Yes | Retention period (how long the facility will hold on to data) expressed in years. | -1 (indefinitely) | -| `ELASTICSEARCH_ENABLED` | string | | Flag to enable/disable the Elasticsearch endpoints. Values "yes" or "no". | "no" | -| `ES_HOST` | string | | Host of Elasticsearch server instance. | | -| `ES_USERNAME` | string | Yes | Elasticsearch username. | "elastic" | -| `ES_PASSWORD` | string | | Elasticsearch password. | | -| `MONGODB_COLLECTION` | string | | Collection name to be mapped into specified Elasticsearch index. Used for data synchronization between MongoDB and Elasticsearch index. | | -| `ES_MAX_RESULT` | number | | Maximum records that can be indexed into Elasticsearch. | 10000 | -| `ES_FIELDS_LIMIT` | number | | The total number of fields in an index. | 1000 | -| `ES_REFRESH` | string | | If set to `wait_for`, Elasticsearch will wait till data is inserted into the specified index before returning a response. | false | -| `LOGGERS_CONFIG_FILE` | string | | The file name for loggers configuration, located in the project root directory. | "loggers.json" | -| `PROPOSAL_TYPES_FILE` | string | | The file name for proposal types configuration, located in the project root directory. | "proposalTypes.json" | -| `SWAGGER_PATH` | string | Yes | swaggerPath is the path where the swagger UI will be available. | "explorer"| -| `MAX_FILE_UPLOAD_SIZE` | string | Yes | Maximum allowed file upload size. | "16mb"| +| `OIDC_FRONTEND_CLIENTS` | string | Yes | Comma separated list of additional frontend OIDC clients for this backend. Example: scilog,maxiv. Their success and return URLs can be configured by setting `OIDC*${CLIENT}_SUCCESS_URL` (E.g. `OIDC_SCILOG_SUCCESS_URL`) and `OIDC_${CLIENT}\_RETURN_URL`| | +|`OIDC_ACCESS_GROUPS`| string | Yes | Functionality is still unclear. | | +|`OIDC_ACCESS_GROUPS_PROPERTY`| string | Yes | Target field to get the access groups value from OIDC response. | | +|`OIDC_USERINFO_MAPPING_FIELD_USERNAME`| string | Yes | Comma-separated list of fields from the OIDC response to use as the user's profile username. Example:`OIDC_USERINFO_MAPPING_FIELD_USERNAME="iss, sub"`. | "preferred_username" \|\| "name" | +| `OIDC_USERINFO_MAPPING_FIELD_DISPLAYNAME`| string | Yes | Field from the OIDC response to use as the user's profile display name. Example:`OIDC_USERINFO_MAPPING_FIELD_DISPLAYNAME="preferred_username"`. | "name" | +| `OIDC_USERINFO_MAPPING_FIELD_EMAIL`| string | Yes | Field from the OIDC response to use as the user's profile email. | "email" | +|`OIDC_USERINFO_MAPPING_FIELD_FAMILYNAME`| string | Yes | Field from the OIDC response to use as the user's profile family name. | "family_name" | +|`OIDC_USERINFO_MAPPING_FIELD_ID`| string | Yes | Field from the OIDC response to use as the user's profile ID. | "sub" \|\| "user_id" | +|`OIDC_USERINFO_MAPPING_FIELD_THUMBNAILPHOTO`| string | Yes | Field from the OIDC response to use as the user's profile thumbnail photo. | "thumbnailPhoto" | +| `OIDC_USERINFO_MAPPING_FIELD_PROVIDER`| string | Yes | Field from the OIDC response to use as the user's profile provider. | "iss" | +|`OIDC_USERINFO_MAPPING_FIELD_GROUP`| string | Yes | Field from the OIDC response to use as the user's profile group. | "groups" | +|`OIDC_USERQUERY_OPERATOR`| string | Yes | Specifies the operator ("or" or "and") for UserModel.findOne queries, determining the logic used to match fields like "username" or "email". Example:`UserModel.findOne({$or: {"username":"testUser", "email":"test@test.com"}})`. | "or" | +| `OIDC_USERQUERY_FILTER`| string | Yes | Defines key-value pairs for UserModel.findOne queries, using a "key:value" format. Example:`OIDC_USERQUERY_FILTER="username:sub, email:email"`. | "username:username, email:email" | +| `LOGBOOK_ENABLED`| string | Yes | Flag to enable/disable the Logbook endpoints. Values "yes" or "no". | "no" | +|`LOGBOOK_BASE_URL`| string | Yes | The base URL to the Logbook API. Only required if Logbook is enabled. | | +|`METADATA_KEYS_RETURN_LIMIT`| number | Yes | The return limit for the`/Datasets/metadataKeys`endpoint. | | +|`METADATA_PARENT_INSTANCES_RETURN_LIMIT`| number | Yes | The return limit of Datasets to extract metadata keys from for the`/Datasets/metadataKeys`endpoint. | | +|`MONGODB_URI`| string | | The URI for your MongoDB instance. | | +|`OAI_PROVIDER_ROUTE`| string | Yes | URI to OAI provider, used for the`/publisheddata/:id/resync`endpoint. | | +|`PID_PREFIX`| string | | The facility PID prefix, with trailing slash. | | +|`PUBLIC_URL_PREFIX`| string | | The base URL to the facility Landing Page. | | +|`PORT`| number | Yes | The port on which you want to access the app. | 3000 | +|`RABBITMQ_ENABLED`| string | Yes | Flag to enable/disable RabbitMQ consumer. Values "yes" or "no". | "no" | +|`RABBITMQ_HOSTNAME`| string | Yes | The hostname of the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | +|`RABBITMQ_USERNAME`| string | Yes | The username used to authenticate to the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | +|`RABBITMQ_PASSWORD`| string | Yes | The password used to authenticate to the RabbitMQ message broker. Only required if RabbitMQ is enabled. | | +|`REGISTER_DOI_URI`| string | | URI to the organization that registers the facility's DOIs. | | +|`REGISTER_METADATA_URI`| string | | URI to the organization that registers the facility's published data metadata. | | +|`SITE`| string | | The name of your site. | | +|`EMAIL_TYPE`| string | Yes | The type of your email provider. Options are "smtp" or "ms365". | "smtp" | +|`EMAIL_FROM`| string | Yes | Email address that emails should be sent from. | | +|`EMAIL_REPLYTO`| string | Yes | Email 'Reply-To' field. | | +|`SMTP_HOST`| string | Yes | Host of SMTP server. | | +|`SMTP_MESSAGE_FROM`| string | Yes | (Deprecated) Alternate spelling of EMAIL_FROM.| | +|`SMTP_PORT`| number | Yes | Port of SMTP server. | 587 | +|`SMTP_SECURE`| bool | Yes | Use encrypted SMTPS. | "no" | +|`MS365_TENANT_ID`| string | Yes | Tenant ID for sending emails over Microsoft Graph API. | | +|`MS365_CLIENT_ID`| string | Yes | Client ID for sending emails over Microsoft Graph API | | +|`MS365_CLIENT_SECRET`| string | Yes | Client Secret for sending emails over Microsoft Graph API | | +|`POLICY_PUBLICATION_SHIFT`| integer | Yes | Embargo period expressed in years. | 3 years | +|`POLICY_RETENTION_SHIFT`| integer | Yes | Retention period (how long the facility will hold on to data) expressed in years. | -1 (indefinitely) | +|`OPENSEARCH_ENABLED`| string | | Controls whether OpenSearch is enabled on application startup. If not provided or set to `no`, OpenSearch will not be instantiated.| "no" | +|`OPENSEARCH_DEFAULT_INDEX`| string | | Specifies the default index. If not provided, a default index named `dataset` will be created automatically. | "dataset" | +|`OPENSEARCH_HOST`| string | | Host of Opensearch server instance. | | +|`OPENSEARCH_USERNAME`| string | Yes | Username for OpenSearch authentication. Defaults to `admin` in standard deployments but can be configured to use a custom user with appropriate permissions. | "admin" | +|`OPENSEARCH_PASSWORD`| string | | Password used for OpenSearch authentication. Must match `OPENSEARCH_INITIAL_ADMIN_PASSWORD` used when creating the OpenSearch container. | | +|`OPENSEARCH_REFRESH`| string | | Controls index refresh behavior. `wait_for`waits for the next refresh cycle before returning, which is useful for development and testing.`false`skips waiting and is recommended for production. Defaults to false. | false | +|`LOGGERS_CONFIG_FILE`| string | | The file name for loggers configuration, located in the project root directory. | "loggers.json" | +|`PROPOSAL_TYPES_FILE`| string | | The file name for proposal types configuration, located in the project root directory. | "proposalTypes.json" | +|`SWAGGER_PATH`| string | Yes | swaggerPath is the path where the swagger UI will be available. | "explorer"| +|`MAX_FILE_UPLOAD_SIZE` | string | Yes | Maximum allowed file upload size. | "16mb"| ## Migrating from the old SciCat Backend diff --git a/eslint.config.mjs b/eslint.config.mjs index 7262a459b..45f098bf3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -73,8 +73,8 @@ export default [ ], "@typescript-eslint/no-unused-vars": [ - "warn", - { "argsIgnorePattern": "^_" }, + "error", + { argsIgnorePattern: "^_" }, ], }, }, diff --git a/migrations/20251117155200-encode-metadatakeys.js b/migrations/20251117155200-encode-metadatakeys.js index c5d20bc44..9d08fea9e 100644 --- a/migrations/20251117155200-encode-metadatakeys.js +++ b/migrations/20251117155200-encode-metadatakeys.js @@ -4,8 +4,20 @@ const { decodeScientificMetadataKeys, } = require("../dist/common/utils"); +/** + * + * This migration encodes the keys of the scientificMetadata field in the Dataset collection + * to ensure they are compatible with MongoDB's key restrictions. The up function encodes the keys, + * while the down function decodes them back to their original form. + */ + module.exports = { async up(db, client) { + let bulkOps = []; + const BATCH_SIZE = 10000; + let modifiedCount = 0; + let unModifiedCount = 0; + for await (const dataset of db .collection("Dataset") .find({ scientificMetadata: { $exists: true } })) { @@ -23,19 +35,43 @@ module.exports = { continue; } - console.log( - `Updating Dataset (Id: ${dataset._id}) with encoded scientificMetadata keys`, - ); - await db - .collection("Dataset") - .updateOne( - { _id: dataset._id }, - { $set: { scientificMetadata: encodedMetadata } }, + bulkOps.push({ + updateOne: { + filter: { _id: dataset._id }, + update: { $set: { scientificMetadata: encodedMetadata } }, + }, + }); + + if (bulkOps.length === BATCH_SIZE) { + const bulkWriteResult = await db.collection("Dataset").bulkWrite(bulkOps, { + ordered: false + }); + modifiedCount += bulkWriteResult.modifiedCount; + unModifiedCount += BATCH_SIZE - bulkWriteResult.modifiedCount; + + bulkOps = []; + console.log("migrating, count, unModifiedCount: ", + modifiedCount, + unModifiedCount, ); - }; + } + } + + if (bulkOps.length > 0) { + console.log(`Executing bulk update for ${bulkOps.length} datasets`); + const bulkWriteResult = await db.collection("Dataset").bulkWrite(bulkOps, { ordered: false }); + modifiedCount += bulkWriteResult.modifiedCount; + unModifiedCount += bulkOps.length - bulkWriteResult.modifiedCount; + } + console.log("FINISHED: count, unModifiedCount: ", modifiedCount, unModifiedCount); }, async down(db, client) { + let bulkOps = []; + const BATCH_SIZE = 10000; + let modifiedCount = 0; + let unModifiedCount = 0; + for await (const dataset of db .collection("Dataset") .find({ scientificMetadata: { $exists: true } })) { @@ -54,15 +90,34 @@ module.exports = { continue; } - console.log( - `Reverting Dataset (Id: ${dataset._id}) to decoded scientificMetadata keys`, - ); - await db - .collection("Dataset") - .updateOne( - { _id: dataset._id }, - { $set: { scientificMetadata: decodedMetadata } }, + bulkOps.push({ + updateOne: { + filter: { _id: dataset._id }, + update: { $set: { scientificMetadata: decodedMetadata } }, + }, + }); + + if (bulkOps.length === BATCH_SIZE) { + const bulkWriteResult = await db.collection("Dataset").bulkWrite(bulkOps, { + ordered: false + }); + modifiedCount += bulkWriteResult.modifiedCount; + unModifiedCount += BATCH_SIZE - bulkWriteResult.modifiedCount; + + bulkOps = []; + console.log("migrating, count, unModifiedCount: ", + modifiedCount, + unModifiedCount, ); - }; + } + } + + if (bulkOps.length > 0) { + console.log(`Executing bulk revert for ${bulkOps.length} datasets`); + const bulkWriteResult = await db.collection("Dataset").bulkWrite(bulkOps, { ordered: false }); + modifiedCount += bulkWriteResult.modifiedCount; + unModifiedCount += bulkOps.length - bulkWriteResult.modifiedCount; + } + console.log("FINISHED: count, unModifiedCount: ", modifiedCount, unModifiedCount); }, }; diff --git a/migrations/20251120153452-add-updatedby-to-instrument.js b/migrations/20251120153452-add-updatedby-to-instrument.js index 3c5cfad64..ee43b520c 100644 --- a/migrations/20251120153452-add-updatedby-to-instrument.js +++ b/migrations/20251120153452-add-updatedby-to-instrument.js @@ -2,13 +2,12 @@ module.exports = { async up(db, client) { await db .collection("Instrument") - .updateMany( - { updatedBy: { $exists: false } }, - [{ $set: { updatedBy: "$createdBy" } }] - ); + .updateMany({ updatedBy: { $exists: false } }, [ + { $set: { updatedBy: "$createdBy" } }, + ]); }, async down(db, client) { // No path backward as it's not easy to find on down where updatedBy was added }, -}; \ No newline at end of file +}; diff --git a/migrations/20260114145500-encode-sample-metadatakeys.js b/migrations/20260114145500-encode-sample-metadatakeys.js new file mode 100644 index 000000000..50513823e --- /dev/null +++ b/migrations/20260114145500-encode-sample-metadatakeys.js @@ -0,0 +1,84 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const { + encodeScientificMetadataKeys, + decodeScientificMetadataKeys, +} = require("../dist/common/utils"); + +module.exports = { + async up(db, client) { + const bulkOps = []; + + for await (const sample of db + .collection("Sample") + .find({ sampleCharacteristics: { $exists: true } })) { + const metadata = sample.sampleCharacteristics; + if (!metadata || typeof metadata !== "object") continue; + + let encodedMetadata; + try { + encodedMetadata = encodeScientificMetadataKeys(metadata); + } catch (err) { + console.error( + `Error encoding sampleCharacteristics for Sample (Id: ${sample._id}):`, + err, + ); + continue; + } + + console.log( + `Updating Sample (Id: ${sample._id}) with encoded sampleCharacteristics keys`, + ); + + bulkOps.push({ + updateOne: { + filter: { _id: sample._id }, + update: { $set: { sampleCharacteristics: encodedMetadata } }, + }, + }); + } + + if (bulkOps.length > 0) { + console.log(`Executing bulk update for ${bulkOps.length} samples`); + await db.collection("Sample").bulkWrite(bulkOps); + } + }, + + async down(db, client) { + const bulkOps = []; + + for await (const sample of db + .collection("Sample") + .find({ sampleCharacteristics: { $exists: true } })) { + const metadata = sample.sampleCharacteristics; + if (!metadata || typeof metadata !== "object") continue; + + let decodedMetadata; + + try { + decodedMetadata = decodeScientificMetadataKeys(metadata); + } catch (err) { + console.error( + `Error decoding sampleCharacteristics for Sample (Id: ${sample._id}):`, + err, + ); + continue; + } + + console.log( + `Reverting Sample (Id: ${sample._id}) to decoded sampleCharacteristics keys`, + ); + + bulkOps.push({ + updateOne: { + filter: { _id: sample._id }, + update: { $set: { sampleCharacteristics: decodedMetadata } }, + }, + }); + } + + if (bulkOps.length > 0) { + console.log(`Executing bulk revert for ${bulkOps.length} samples`); + await db.collection("Sample").bulkWrite(bulkOps); + } + }, +}; diff --git a/opensearchConfig.example.json b/opensearchConfig.example.json new file mode 100644 index 000000000..5e851410a --- /dev/null +++ b/opensearchConfig.example.json @@ -0,0 +1,64 @@ +{ + "settings": { + "index": { + "max_result_window": 2000000, + "number_of_replicas": 0 + }, + "analysis": { + "analyzer": { + "autocomplete": { + "type": "custom", + "tokenizer": "autocomplete", + "filter": ["word_delimiter", "lowercase"] + }, + "autocomplete_search": { + "type": "custom", + "tokenizer": "keyword", + "filter": ["lowercase"] + } + }, + "tokenizer": { + "autocomplete": { + "type": "edge_ngram", + "min_gram": 2, + "max_gram": 150, + "token_chars": ["letter", "digit", "symbol", "punctuation"] + } + }, + "filter": { + "word_delimiter": { + "type": "word_delimiter_graph", + "split_on_case_change": false, + "split_on_numerics": false, + "preserve_original": true, + "type_table": [". => ALPHA"] + } + } + } + }, + "mappings": { + "properties": { + "description": { + "type": "text", + "analyzer": "autocomplete", + "search_analyzer": "autocomplete_search" + }, + "datasetName": { + "type": "text", + "analyzer": "autocomplete", + "search_analyzer": "autocomplete_search" + }, + "isPublished": { + "type": "boolean" + }, + "ownerGroup": { + "type": "keyword", + "ignore_above": 256 + }, + "accessGroups": { + "type": "keyword", + "ignore_above": 256 + } + } + } +} diff --git a/package-lock.json b/package-lock.json index c5d752d8a..78f73778c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,13 +11,11 @@ "dependencies": { "@casl/ability": "^6.3.2", "@casl/mongoose": "^8.0.4", - "@elastic/elasticsearch": "^8.15.0", "@nestjs-modules/mailer": "^2", "@nestjs/axios": "^4", "@nestjs/common": "^11", "@nestjs/config": "^4", "@nestjs/core": "^11", - "@nestjs/elasticsearch": "^11", "@nestjs/event-emitter": "^3", "@nestjs/jwt": "^11", "@nestjs/mongoose": "^11.0.4", @@ -25,15 +23,19 @@ "@nestjs/platform-express": "^11", "@nestjs/swagger": "^11.1.1", "@nestjs/terminus": "^11", + "@nestjs/throttler": "^6.5.0", + "@opensearch-project/opensearch": "^3.5.1", "@types/json-merge-patch": "^1.0.0", "@types/jsonschema": "^1.1.1", "@user-office-software/duo-logger": "^2.1.1", "@user-office-software/duo-message-broker": "^1.4.0", - "ajv": "^8.12.0", - "amqplib": "^0.10.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", + "amqplib": "^1.0.2", "bcrypt": "^6.0.0", "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", + "class-validator": "^0.15.1", "connect-mongo": "^6.0.0", "dotenv": "^17.2.0", "express-session": "^1.17.3", @@ -83,7 +85,7 @@ "@types/nodemailer": "^7.0.1", "@types/passport-jwt": "^4.0.0", "@types/passport-local": "^1.0.34", - "@types/supertest": "^6.0.1", + "@types/supertest": "^7.2.0", "@types/uuid": "^11.0.0", "@typescript-eslint/eslint-plugin": "^8.1.0", "@typescript-eslint/parser": "^8.1.0", @@ -91,7 +93,7 @@ "chai-http": "^5.1.1", "concurrently": "^9.0.0", "dotenv-cli": "^11.0.0", - "eslint": "^9.0.0", + "eslint": "^10.0.3", "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.0.0", "globals": "^17.0.0", @@ -109,65 +111,14 @@ "wait-on": "^9.0.1" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.19.tgz", - "integrity": "sha512-JbLL+4IMLMBgjLZlnPG4lYDfz4zGrJ/s6Aoon321NJKuw1Kb1k5KpFu9dUY0BqLIe8xPQ2UJBpI+xXdK5MXMHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/schematics": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.19.tgz", - "integrity": "sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==", + "version": "19.2.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.22.tgz", + "integrity": "sha512-tvfu5jhem1o8qidVxvXe5KfCij65ioMLCOFA947DD+zb3yTl5pJyDm2dqzbOehuQw0fmH4XPQukRJsCUy+UwaA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", + "@angular-devkit/core": "19.2.22", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "5.4.1", @@ -180,14 +131,14 @@ } }, "node_modules/@angular-devkit/schematics-cli": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.19.tgz", - "integrity": "sha512-7q9UY6HK6sccL9F3cqGRUwKhM7b/XfD2YcVaZ2WD7VMaRlRm85v6mRjSrfKIAwxcQU0UK27kMc79NIIqaHjzxA==", + "version": "19.2.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.22.tgz", + "integrity": "sha512-6BvkxDz4nV8B6Ha4n/pYZ503vXgLxMaEpcKsFDao1sl0iSwrIOphlIS1yWprlGdCThIM3aJref1JU13ZvEcBCA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", - "@angular-devkit/schematics": "19.2.19", + "@angular-devkit/core": "19.2.22", + "@angular-devkit/schematics": "19.2.22", "@inquirer/prompts": "7.3.2", "ansi-colors": "4.1.3", "symbol-observable": "4.0.0", @@ -202,6 +153,34 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/core": { + "version": "19.2.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.22.tgz", + "integrity": "sha512-OqN/Ded+ZKypPZN5+qUFwtnKGl7FKpxJXYO2Vts5vLBojY5goCZd9SGW1CyXeuPnisRUW+vjqBQbWYuEUh36Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, "node_modules/@angular-devkit/schematics-cli/node_modules/@inquirer/prompts": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.3.2.tgz", @@ -232,7 +211,7 @@ } } }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", @@ -242,1873 +221,1511 @@ "tslib": "^2.1.0" } }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { + "version": "19.2.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.22.tgz", + "integrity": "sha512-OqN/Ded+ZKypPZN5+qUFwtnKGl7FKpxJXYO2Vts5vLBojY5goCZd9SGW1CyXeuPnisRUW+vjqBQbWYuEUh36Tw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": ">=14.0.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" + "tslib": "^2.1.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, + "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@aws-sdk/client-sesv2": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sesv2/-/client-sesv2-3.876.0.tgz", - "integrity": "sha512-cu8yNNX5q07K+81lMN5KR6iMduql0rX3SRYdOVcjOZ/35amPn4Q+Dyqs8guIhBupRMCxROmilpS5EMpe3QTqOA==", + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.876.0", - "@aws-sdk/credential-provider-node": "3.876.0", - "@aws-sdk/middleware-host-header": "3.873.0", - "@aws-sdk/middleware-logger": "3.876.0", - "@aws-sdk/middleware-recursion-detection": "3.873.0", - "@aws-sdk/middleware-user-agent": "3.876.0", - "@aws-sdk/region-config-resolver": "3.873.0", - "@aws-sdk/signature-v4-multi-region": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@aws-sdk/util-endpoints": "3.873.0", - "@aws-sdk/util-user-agent-browser": "3.873.0", - "@aws-sdk/util-user-agent-node": "3.876.0", - "@smithy/config-resolver": "^4.1.5", - "@smithy/core": "^3.8.0", - "@smithy/fetch-http-handler": "^5.1.1", - "@smithy/hash-node": "^4.0.5", - "@smithy/invalid-dependency": "^4.0.5", - "@smithy/middleware-content-length": "^4.0.5", - "@smithy/middleware-endpoint": "^4.1.18", - "@smithy/middleware-retry": "^4.1.19", - "@smithy/middleware-serde": "^4.0.9", - "@smithy/middleware-stack": "^4.0.5", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/node-http-handler": "^4.1.1", - "@smithy/protocol-http": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.26", - "@smithy/util-defaults-mode-node": "^4.0.26", - "@smithy/util-endpoints": "^3.0.7", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-retry": "^4.0.7", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.876.0.tgz", - "integrity": "sha512-Vf0PMF7HVpvllrfPODnBZmlz6kT/y2AvOt1RQG3+qD0VrHWzShc5nwgRZ+yyP3xkKVhZsQ3sJapfZTFnjqMOYA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.876.0", - "@aws-sdk/middleware-host-header": "3.873.0", - "@aws-sdk/middleware-logger": "3.876.0", - "@aws-sdk/middleware-recursion-detection": "3.873.0", - "@aws-sdk/middleware-user-agent": "3.876.0", - "@aws-sdk/region-config-resolver": "3.873.0", - "@aws-sdk/types": "3.862.0", - "@aws-sdk/util-endpoints": "3.873.0", - "@aws-sdk/util-user-agent-browser": "3.873.0", - "@aws-sdk/util-user-agent-node": "3.876.0", - "@smithy/config-resolver": "^4.1.5", - "@smithy/core": "^3.8.0", - "@smithy/fetch-http-handler": "^5.1.1", - "@smithy/hash-node": "^4.0.5", - "@smithy/invalid-dependency": "^4.0.5", - "@smithy/middleware-content-length": "^4.0.5", - "@smithy/middleware-endpoint": "^4.1.18", - "@smithy/middleware-retry": "^4.1.19", - "@smithy/middleware-serde": "^4.0.9", - "@smithy/middleware-stack": "^4.0.5", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/node-http-handler": "^4.1.1", - "@smithy/protocol-http": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.26", - "@smithy/util-defaults-mode-node": "^4.0.26", - "@smithy/util-endpoints": "^3.0.7", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-retry": "^4.0.7", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/core": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.876.0.tgz", - "integrity": "sha512-sVFBFkdoPOPyY13NaXO1E/R9O5J6ixzHnnRbqrbXYM2QQgLNPTKIiRtmVEuVoFV9YULg+/aKm7caix8m468y9w==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@aws-sdk/xml-builder": "3.873.0", - "@smithy/core": "^3.8.0", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/property-provider": "^4.0.5", - "@smithy/protocol-http": "^5.1.3", - "@smithy/signature-v4": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "5.2.5", - "tslib": "^2.6.2" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.876.0.tgz", - "integrity": "sha512-cof7lwp2AlrAfRs0pt4W2KMS2VMBvEmpcti1UOFfSJIqkn+cyJliMJ8LHg22GI+kUexjvxdAqSbf3M7OHvEW+w==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/property-provider": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.876.0.tgz", - "integrity": "sha512-wzmef2NBp2+X1l8D4Q8hx1G8oI3+WdvLdPev9VnVpRYZxYGRWVPl++wvCBsCn/ZL0mdWopPkhHA3kFexQhMzvg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/fetch-http-handler": "^5.1.1", - "@smithy/node-http-handler": "^4.1.1", - "@smithy/property-provider": "^4.0.5", - "@smithy/protocol-http": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/util-stream": "^4.2.4", - "tslib": "^2.6.2" - }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.876.0.tgz", - "integrity": "sha512-JHbW6fqnJsVjGHCyko7B0NVPT1nEAPxkM3CGjUcVGsHgJBkxOLVCMQqTRyHcDdeHR2qeojlLoOHRz97xIHQjYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/credential-provider-env": "3.876.0", - "@aws-sdk/credential-provider-http": "3.876.0", - "@aws-sdk/credential-provider-process": "3.876.0", - "@aws-sdk/credential-provider-sso": "3.876.0", - "@aws-sdk/credential-provider-web-identity": "3.876.0", - "@aws-sdk/nested-clients": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/credential-provider-imds": "^4.0.7", - "@smithy/property-provider": "^4.0.5", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.876.0.tgz", - "integrity": "sha512-eHbNt1+Hi43e8ANnwf6toapLSxfMiyGq459y3Uh6i7NBOiWWKEsOVcgOfUC3RCoqeikxovt1tFM2cEElWUIOhg==", + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.876.0", - "@aws-sdk/credential-provider-http": "3.876.0", - "@aws-sdk/credential-provider-ini": "3.876.0", - "@aws-sdk/credential-provider-process": "3.876.0", - "@aws-sdk/credential-provider-sso": "3.876.0", - "@aws-sdk/credential-provider-web-identity": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/credential-provider-imds": "^4.0.7", - "@smithy/property-provider": "^4.0.5", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.876.0.tgz", - "integrity": "sha512-SMX4OlHvspu3gF4hxe7WAnZFhxpiCye+WlBSVoWfW/i9XNhtrZS1JMr29MK34GlCTk9qO7FlRwds/Z5k7xPpHg==", + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/property-provider": "^4.0.5", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.876.0.tgz", - "integrity": "sha512-iP5dz9XqwePbgnh7Bdrq5e1319JpCRKLyomUfHH1XVeXkIHmwIJdmTj1Upeo1J8L/5cLHmhXAN6CTN11bLo8SA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@aws-sdk/client-sso": "3.876.0", - "@aws-sdk/core": "3.876.0", - "@aws-sdk/token-providers": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/property-provider": "^4.0.5", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.0.0" } }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.876.0.tgz", - "integrity": "sha512-q/XSCP1uae5aB9veM8zcm6Gqu6A4ckX9ZbhHgCzURXVJDwp+nINW1hM9vppMjGw3ND9Ibx/adR+KfTI0TDMzqw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/nested-clients": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/property-provider": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.873.0.tgz", - "integrity": "sha512-KZ/W1uruWtMOs7D5j3KquOxzCnV79KQW9MjJFZM/M0l6KI8J6V3718MXxFHsTjUE4fpdV6SeCNLV1lwGygsjJA==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.876.0.tgz", - "integrity": "sha512-cpWJhOuMSyz9oV25Z/CMHCBTgafDCbv7fHR80nlRrPdPZ8ETNsahwRgltXP1QJJ8r3X/c1kwpOR7tc+RabVzNA==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.873.0.tgz", - "integrity": "sha512-OtgY8EXOzRdEWR//WfPkA/fXl0+WwE8hq0y9iw2caNyKPtca85dzrrZWnPqyBK/cpImosrpR1iKMYr41XshsCg==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.12.13" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.876.0.tgz", - "integrity": "sha512-h+TDs9EKAfXnrkogQpQz3o11zvs6Vh9+ehxyd35OcM7evnDeoV4GFjjnAKq+MxbBk/5Ewnvng+d6/WQDvMbj7Q==", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@aws-sdk/util-arn-parser": "3.873.0", - "@smithy/core": "^3.8.0", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/protocol-http": "^5.1.3", - "@smithy/signature-v4": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-stream": "^4.2.4", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.876.0.tgz", - "integrity": "sha512-FR+8INfnbNv32QDQ5szxkWX6mB/QgezfNyx8LnAh1ErISZMmEFBxXXir+ZOfuV8vsmal1a6cy9qmnMNDaNnaNQ==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@aws-sdk/util-endpoints": "3.873.0", - "@smithy/core": "^3.8.0", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.876.0.tgz", - "integrity": "sha512-R4TZrkM2gUElTsotk8mt3y7iLG8TNi1LL1wgVdEEWSLOYTaFyglGdoNBMtEeP7lmXilaTy00AbYF6BakJvSTHg==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.876.0", - "@aws-sdk/middleware-host-header": "3.873.0", - "@aws-sdk/middleware-logger": "3.876.0", - "@aws-sdk/middleware-recursion-detection": "3.873.0", - "@aws-sdk/middleware-user-agent": "3.876.0", - "@aws-sdk/region-config-resolver": "3.873.0", - "@aws-sdk/types": "3.862.0", - "@aws-sdk/util-endpoints": "3.873.0", - "@aws-sdk/util-user-agent-browser": "3.873.0", - "@aws-sdk/util-user-agent-node": "3.876.0", - "@smithy/config-resolver": "^4.1.5", - "@smithy/core": "^3.8.0", - "@smithy/fetch-http-handler": "^5.1.1", - "@smithy/hash-node": "^4.0.5", - "@smithy/invalid-dependency": "^4.0.5", - "@smithy/middleware-content-length": "^4.0.5", - "@smithy/middleware-endpoint": "^4.1.18", - "@smithy/middleware-retry": "^4.1.19", - "@smithy/middleware-serde": "^4.0.9", - "@smithy/middleware-stack": "^4.0.5", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/node-http-handler": "^4.1.1", - "@smithy/protocol-http": "^5.1.3", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.26", - "@smithy/util-defaults-mode-node": "^4.0.26", - "@smithy/util-endpoints": "^3.0.7", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-retry": "^4.0.7", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.873.0.tgz", - "integrity": "sha512-q9sPoef+BBG6PJnc4x60vK/bfVwvRWsPgcoQyIra057S/QGjq5VkjvNk6H8xedf6vnKlXNBwq9BaANBXnldUJg==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/types": "^4.3.2", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.5", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.876.0.tgz", - "integrity": "sha512-OMDcuaVlC2rbze92w4QcNfuEA0IeT2GsT1ByZCwe+Y9tZwxzj7fCiOOU0UmJfa+juuQ/YBzVYxnkrkz3Rg6DEw==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/protocol-http": "^5.1.3", - "@smithy/signature-v4": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.876.0.tgz", - "integrity": "sha512-iU08kaQbhXnY0CC2TBcr7y/2PqPwZP2CTWX/Rbq0NvhOyteikfh7ASC+bRfLUp0XMSHKvSb+w2dh8a0lvx4oHg==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/core": "3.876.0", - "@aws-sdk/nested-clients": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/property-provider": "^4.0.5", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/types": { - "version": "3.862.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.862.0.tgz", - "integrity": "sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.873.0.tgz", - "integrity": "sha512-qag+VTqnJWDn8zTAXX4wiVioa0hZDQMtbZcGRERVnLar4/3/VIKBhxX2XibNQXFu1ufgcRn4YntT/XEPecFWcg==", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.873.0.tgz", - "integrity": "sha512-YByHrhjxYdjKRf/RQygRK1uh0As1FIi9+jXTcIEX/rBgN8mUByczr2u4QXBzw7ZdbdcOBMOkPnLRjNOWW1MkFg==", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "@smithy/util-endpoints": "^3.0.7", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.873.0.tgz", - "integrity": "sha512-xcVhZF6svjM5Rj89T1WzkjQmrTF6dpR2UvIHPMTnSZoNe6CixejPZ6f0JJ2kAhO8H+dUHwNBlsUgOTIKiK/Syg==", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.873.0.tgz", - "integrity": "sha512-AcRdbK6o19yehEcywI43blIBhOCSo6UgyWcuOJX5CFF8k39xm1ILCjQlRRjchLAxWrm0lU0Q7XV90RiMMFMZtA==", + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.862.0", - "@smithy/types": "^4.3.2", - "bowser": "^2.11.0", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.876.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.876.0.tgz", - "integrity": "sha512-/ZIaeUt60JBdI0mNc7sZ8v3Tuzp8Pbe4gIAYnppGyF4KV8QA+Yu8tp2bGHfkKn150t1uvQ6P/4CwFfoGF34dzg==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.876.0", - "@aws-sdk/types": "3.862.0", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } + "@babel/core": "^7.0.0-0" } }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.873.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.873.0.tgz", - "integrity": "sha512-kLO7k7cGJ6KaHiExSJWojZurF7SnGMDHXRuQunFnEoD0n1yB6Lqy/S/zHiQ7oJnBhPr9q0TW9qFkrsZb1Uc54w==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", - "dev": true, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" } }, - "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "devOptional": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "license": "MIT" }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", "license": "MIT", - "engines": { - "node": ">=6.9.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, + "node_modules/@casl/ability": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@casl/ability/-/ability-6.8.0.tgz", + "integrity": "sha512-Ipt4mzI4gSgnomFdaPjaLgY2MWuXqAEZLrU6qqWBB7khGiBBuuEp6ytYDnq09bRXqcjaeeHiaCvCGFbBA2SpvA==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@ucast/mongo2js": "^1.3.0" }, + "funding": { + "url": "https://github.com/stalniy/casl/blob/master/BACKERS.md" + } + }, + "node_modules/@casl/mongoose": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/@casl/mongoose/-/mongoose-8.0.5.tgz", + "integrity": "sha512-dCUFBtNFLBKH01eDKFfC0DXfZGQimtFkxfzMfRAuURkbRM7aYOKzr3Yd5dTe30q2sDP6ocLtFKA0YM5DcprBnw==", + "license": "MIT", + "peerDependencies": { + "@casl/ability": "^6.7.0", + "mongoose": "^6.0.13 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", + "optional": true, "engines": { - "node": ">=6.9.0" + "node": ">=0.1.90" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=12" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@css-inline/css-inline": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.20.0.tgz", + "integrity": "sha512-WABsvMSBs/DDadwhAUDw6uXwUE6w4DC/bnC4E2Y2rqbCTw5E1PPfj6VksnSCALkv9ynZfYGYYO4+Rvhmn5kgpw==", + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 10" + }, + "optionalDependencies": { + "@css-inline/css-inline-android-arm-eabi": "0.20.0", + "@css-inline/css-inline-android-arm64": "0.20.0", + "@css-inline/css-inline-darwin-arm64": "0.20.0", + "@css-inline/css-inline-darwin-x64": "0.20.0", + "@css-inline/css-inline-linux-arm-gnueabihf": "0.20.0", + "@css-inline/css-inline-linux-arm64-gnu": "0.20.0", + "@css-inline/css-inline-linux-arm64-musl": "0.20.0", + "@css-inline/css-inline-linux-x64-gnu": "0.20.0", + "@css-inline/css-inline-linux-x64-musl": "0.20.0", + "@css-inline/css-inline-win32-arm64-msvc": "0.20.0", + "@css-inline/css-inline-win32-x64-msvc": "0.20.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "devOptional": true, + "node_modules/@css-inline/css-inline-android-arm-eabi": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm-eabi/-/css-inline-android-arm-eabi-0.20.0.tgz", + "integrity": "sha512-w1+cicyd2xGzuOcFYxL9Yp3E/KT6opGpdhaKo1vFAepyn8zHrpAR3c1DHH1RWSWK3ZVcD3ne1naqJXQa4k/9uw==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "devOptional": true, + "node_modules/@css-inline/css-inline-android-arm64": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm64/-/css-inline-android-arm64-0.20.0.tgz", + "integrity": "sha512-V6ELV+DEjhYPqRcyCezUcMDSrXINMSCL4RBseEqWG18WhOZ9GoGd5XFpZzciQhHq/2MQS+06Jcc6RX59k7QS5g==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, + "node_modules/@css-inline/css-inline-darwin-arm64": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.20.0.tgz", + "integrity": "sha512-hT8Mtwp4PJ9mMYFDG/xg7KCa7nPqseJdXaajxXVjXB8+6oemxgx+7TUO7HSfmeY4Ox7X2vaNfaIfti4ySgNvyg==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@babel/helpers": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", - "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", - "dev": true, + "node_modules/@css-inline/css-inline-darwin-x64": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.20.0.tgz", + "integrity": "sha512-caFvVySabHZG4N1QUysbhWp2+VstMlYLysZYfAX0I6c9QfWcr+OZThoGOO2gC9lYy6QMCTBSD+9t+iceH9oBQw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", - "devOptional": true, + "node_modules/@css-inline/css-inline-linux-arm-gnueabihf": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.20.0.tgz", + "integrity": "sha512-9/TdB6cHgJ285uL7Y+1XjdJGjIQOeF9/YNq47N+azf2SiYdA3ahGYBmZhCGtYG7aBTJly9iJCxjP9ZZN8+Lajw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, + "node_modules/@css-inline/css-inline-linux-arm64-gnu": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.20.0.tgz", + "integrity": "sha512-umcG26teSSUxWGQm7sECI8KweUgBgq9Cqd6yNMTNzqC1K56ZhW3Iwi7QewVNGOpVPXoGsywIIwIuY9lyed1Jdw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, + "node_modules/@css-inline/css-inline-linux-arm64-musl": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.20.0.tgz", + "integrity": "sha512-wHQykZw3pX2R5Yp5VChOWzVXXO3XPdgWkQH1B9QBmft926EOkZpwxvubeAYy9I89qJzzdGNqiRl26+AUP88J3A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, + "node_modules/@css-inline/css-inline-linux-x64-gnu": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.20.0.tgz", + "integrity": "sha512-lHQZ+31CN3XJTn5MMFv1NYjyvuhAWEvul0fAYyppw4haA1TM+9UuA9jXdjqWXp26ItmainUnDMBlNLYQwMYt7g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, + "node_modules/@css-inline/css-inline-linux-x64-musl": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.20.0.tgz", + "integrity": "sha512-DO/cba/zndTY3s86nNNfeHx7DvrvLb+IxhkQWTr29IQeiUgbawCH9X3B/4Li2eo/sEx/imOOnYDdXYu8PeX2Fg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, + "node_modules/@css-inline/css-inline-win32-arm64-msvc": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-arm64-msvc/-/css-inline-win32-arm64-msvc-0.20.0.tgz", + "integrity": "sha512-1o8xla5ljVHS7SguH6nTV6uoAIMRZv+2MrcxfLRObpkUtCO7oKXDeWnia7XlmnLhDX8Ncx5bDOenZb1N35kCiA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, + "node_modules/@css-inline/css-inline-win32-x64-msvc": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.20.0.tgz", + "integrity": "sha512-pdO/QXLRwuq/RxO5PSFMhmWGJSQOvkiDyV4RrewEkE7SOCY8HAYNhx1T0y0pj2WzxuVdbNQbpwiCHAdQNplUJw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=6.9.0" + "node": "18 || 20 || >=22" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "regenerator-runtime": "^0.14.0" + "@eslint/core": "^1.2.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", - "debug": "^4.3.1" + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", - "devOptional": true, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=6.9.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "MIT" - }, - "node_modules/@casl/ability": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@casl/ability/-/ability-6.8.0.tgz", - "integrity": "sha512-Ipt4mzI4gSgnomFdaPjaLgY2MWuXqAEZLrU6qqWBB7khGiBBuuEp6ytYDnq09bRXqcjaeeHiaCvCGFbBA2SpvA==", "license": "MIT", - "dependencies": { - "@ucast/mongo2js": "^1.3.0" + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/stalniy/casl/blob/master/BACKERS.md" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@casl/mongoose": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@casl/mongoose/-/mongoose-8.0.5.tgz", - "integrity": "sha512-dCUFBtNFLBKH01eDKFfC0DXfZGQimtFkxfzMfRAuURkbRM7aYOKzr3Yd5dTe30q2sDP6ocLtFKA0YM5DcprBnw==", + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@casl/ability": "^6.7.0", - "mongoose": "^6.0.13 || ^7.0.0 || ^8.0.0 || ^9.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "optional": true, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=0.1.90" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@faker-js/faker": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", + "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@css-inline/css-inline": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.14.1.tgz", - "integrity": "sha512-u4eku+hnPqqHIGq/ZUQcaP0TrCbYeLIYBaK7qClNRGZbnh8RC4gVxLEIo8Pceo1nOK9E5G4Lxzlw5KnXcvflfA==", - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@css-inline/css-inline-android-arm-eabi": "0.14.1", - "@css-inline/css-inline-android-arm64": "0.14.1", - "@css-inline/css-inline-darwin-arm64": "0.14.1", - "@css-inline/css-inline-darwin-x64": "0.14.1", - "@css-inline/css-inline-linux-arm-gnueabihf": "0.14.1", - "@css-inline/css-inline-linux-arm64-gnu": "0.14.1", - "@css-inline/css-inline-linux-arm64-musl": "0.14.1", - "@css-inline/css-inline-linux-x64-gnu": "0.14.1", - "@css-inline/css-inline-linux-x64-musl": "0.14.1", - "@css-inline/css-inline-win32-x64-msvc": "0.14.1" - } - }, - "node_modules/@css-inline/css-inline-android-arm-eabi": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm-eabi/-/css-inline-android-arm-eabi-0.14.1.tgz", - "integrity": "sha512-LNUR8TY4ldfYi0mi/d4UNuHJ+3o8yLQH9r2Nt6i4qeg1i7xswfL3n/LDLRXvGjBYqeEYNlhlBQzbPwMX1qrU6A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@css-inline/css-inline-android-arm64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm64/-/css-inline-android-arm64-0.14.1.tgz", - "integrity": "sha512-tH5us0NYGoTNBHOUHVV7j9KfJ4DtFOeTLA3cM0XNoMtArNu2pmaaBMFJPqECzavfXkLc7x5Z22UPZYjoyHfvCA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@css-inline/css-inline-darwin-arm64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.14.1.tgz", - "integrity": "sha512-QE5W1YRIfRayFrtrcK/wqEaxNaqLULPI0gZB4ArbFRd3d56IycvgBasDTHPre5qL2cXCO3VyPx+80XyHOaVkag==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" } }, - "node_modules/@css-inline/css-inline-darwin-x64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.14.1.tgz", - "integrity": "sha512-mAvv2sN8awNFsbvBzlFkZPbCNZ6GCWY5/YcIz7V5dPYw+bHHRbjnlkNTEZq5BsDxErVrMIGvz05PGgzuNvZvdQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@hapi/address": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", + "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" + }, "engines": { - "node": ">= 10" + "node": ">=14.0.0" } }, - "node_modules/@css-inline/css-inline-linux-arm-gnueabihf": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.14.1.tgz", - "integrity": "sha512-AWC44xL0X7BgKvrWEqfSqkT2tJA5kwSGrAGT+m0gt11wnTYySvQ6YpX0fTY9i3ppYGu4bEdXFjyK2uY1DTQMHA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "node_modules/@hapi/formula": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", + "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/@css-inline/css-inline-linux-arm64-gnu": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.14.1.tgz", - "integrity": "sha512-drj0ciiJgdP3xKXvNAt4W+FH4KKMs8vB5iKLJ3HcH07sNZj58Sx++2GxFRS1el3p+GFp9OoYA6dgouJsGEqt0Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "node_modules/@hapi/hoek": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", + "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/@css-inline/css-inline-linux-arm64-musl": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.14.1.tgz", - "integrity": "sha512-FzknI+st8eA8YQSdEJU9ykcM0LZjjigBuynVF5/p7hiMm9OMP8aNhWbhZ8LKJpKbZrQsxSGS4g9Vnr6n6FiSdQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "node_modules/@hapi/pinpoint": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", + "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/@css-inline/css-inline-linux-x64-gnu": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.14.1.tgz", - "integrity": "sha512-yubbEye+daDY/4vXnyASAxH88s256pPati1DfVoZpU1V0+KP0BZ1dByZOU1ktExurbPH3gZOWisAnBE9xon0Uw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/@hapi/tlds": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", + "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 10" + "node": ">=14.0.0" } }, - "node_modules/@css-inline/css-inline-linux-x64-musl": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.14.1.tgz", - "integrity": "sha512-6CRAZzoy1dMLPC/tns2rTt1ZwPo0nL/jYBEIAsYTCWhfAnNnpoLKVh5Nm+fSU3OOwTTqU87UkGrFJhObD/wobQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "node_modules/@hapi/topo": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", + "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" } }, - "node_modules/@css-inline/css-inline-win32-x64-msvc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.14.1.tgz", - "integrity": "sha512-nzotGiaiuiQW78EzsiwsHZXbxEt6DiMUFcDJ6dhiliomXxnlaPyBfZb6/FMBgRJOf6sknDt/5695OttNmbMYzg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 10" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "license": "MIT", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" + "node": ">=18.18.0" } }, - "node_modules/@elastic/elasticsearch": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.19.1.tgz", - "integrity": "sha512-+1j9NnQVOX+lbWB8LhCM7IkUmjU05Y4+BmSLfusq0msCsQb1Va+OUKFCoOXjCJqQrcgdRdQCjYYyolQ/npQALQ==", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@elastic/transport": "^8.9.6", - "apache-arrow": "18.x - 21.x", - "tslib": "^2.4.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@elastic/transport": { - "version": "8.9.6", - "resolved": "https://registry.npmjs.org/@elastic/transport/-/transport-8.9.6.tgz", - "integrity": "sha512-v71jgmZtgPg2ouXF5KTPxU1a6z7YYc8nazAS7jLySteC/vrShs1OJh6oEEeo5oDc19MYUofV/JV1h5vqJVBXOw==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "1.x", - "debug": "^4.4.0", - "hpagent": "^1.2.0", - "ms": "^2.1.3", - "secure-json-parse": "^3.0.1", - "tslib": "^2.8.1", - "undici": "^6.21.1" - }, "engines": { - "node": ">=18" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "engines": { + "node": ">=18" } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, "engines": { "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" }, - "funding": { - "url": "https://eslint.org/donate" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@faker-js/faker": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.2.0.tgz", - "integrity": "sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/fakerjs" - } - ], - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", - "npm": ">=10" - } - }, - "node_modules/@hapi/address": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/formula": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/hoek": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/pinpoint": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/tlds": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.3.tgz", - "integrity": "sha512-QIvUMB5VZ8HMLZF9A2oWr3AFM430QC8oGd0L35y2jHpuW6bIIca6x/xL7zUf4J7L9WJ3qjz+iJII8ncaeMbpSg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/topo": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@inquirer/ansi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", - "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/checkbox": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", - "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", @@ -2126,15 +1743,18 @@ } } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", - "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2148,22 +1768,12 @@ } } }, - "node_modules/@inquirer/core": { - "version": "10.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", - "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.3" - }, "engines": { "node": ">=18" }, @@ -2176,361 +1786,97 @@ } } }, - "node_modules/@inquirer/editor": { - "version": "4.2.23", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", - "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", - "dev": true, - "license": "MIT", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "devOptional": true, + "license": "ISC", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/external-editor": "^1.0.3", - "@inquirer/type": "^3.0.10" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=12" } }, - "node_modules/@inquirer/expand": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", - "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", - "dev": true, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "devOptional": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": ">=12" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", - "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", - "dev": true, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "devOptional": true, "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": ">=12" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", - "dev": true, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "devOptional": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@inquirer/figures": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", - "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/input": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", - "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/number": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", - "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/password": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", - "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/rawlist": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", - "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/search": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", - "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/select": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", - "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/type": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", - "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "devOptional": true, "license": "MIT", "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "devOptional": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2595,9 +1941,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -2665,22 +2011,23 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", - "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", + "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.3.0", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", "slash": "^3.0.0" }, "engines": { @@ -2688,39 +2035,38 @@ } }, "node_modules/@jest/core": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", - "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", + "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", + "@jest/console": "30.3.0", "@jest/pattern": "30.0.1", - "@jest/reporters": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/reporters": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "ci-info": "^4.2.0", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-changed-files": "30.2.0", - "jest-config": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", + "jest-changed-files": "30.3.0", + "jest-config": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-resolve-dependencies": "30.2.0", - "jest-runner": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "jest-watcher": "30.2.0", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", + "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" }, "engines": { @@ -2735,26 +2081,10 @@ } } }, - "node_modules/@jest/core/node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", "dev": true, "license": "MIT", "engines": { @@ -2762,39 +2092,39 @@ } }, "node_modules/@jest/environment": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", - "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", + "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "jest-mock": "30.2.0" + "jest-mock": "30.3.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.2.0", - "jest-snapshot": "30.2.0" + "expect": "30.3.0", + "jest-snapshot": "30.3.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", "dev": true, "license": "MIT", "dependencies": { @@ -2805,18 +2135,18 @@ } }, "node_modules/@jest/fake-timers": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", - "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", + "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@sinonjs/fake-timers": "^13.0.0", + "@jest/types": "30.3.0", + "@sinonjs/fake-timers": "^15.0.0", "@types/node": "*", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -2833,16 +2163,16 @@ } }, "node_modules/@jest/globals": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", - "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", + "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/types": "30.2.0", - "jest-mock": "30.2.0" + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/types": "30.3.0", + "jest-mock": "30.3.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -2863,32 +2193,32 @@ } }, "node_modules/@jest/reporters": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", - "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", + "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@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.25", "@types/node": "*", "chalk": "^4.1.2", "collect-v8-coverage": "^1.0.2", "exit-x": "^0.2.2", - "glob": "^10.3.10", + "glob": "^10.5.0", "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "jest-worker": "30.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.0.1" @@ -2905,6 +2235,78 @@ } } }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jest/schemas": { "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", @@ -2919,13 +2321,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", - "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", + "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.3.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -2950,14 +2352,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", - "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", + "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", - "@jest/types": "30.2.0", + "@jest/console": "30.3.0", + "@jest/types": "30.3.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -2966,15 +2368,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", - "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", + "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.2.0", + "@jest/test-result": "30.3.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", + "jest-haste-map": "30.3.0", "slash": "^3.0.0" }, "engines": { @@ -2982,24 +2384,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", - "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", + "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.2.0", + "@jest/types": "30.3.0", "@jridgewell/trace-mapping": "^0.3.25", "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.2.0", + "jest-haste-map": "30.3.0", "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "micromatch": "^4.0.8", + "jest-util": "30.3.0", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" @@ -3009,9 +2410,9 @@ } }, "node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", "dev": true, "license": "MIT", "dependencies": { @@ -3028,21 +2429,33 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -3051,7 +2464,7 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3059,16 +2472,17 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "devOptional": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3079,6 +2493,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -3090,6 +2505,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", "engines": { "node": ">= 10.16.0" }, @@ -3101,6 +2517,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", "engines": { "node": ">=8" } @@ -3112,9 +2529,9 @@ "license": "MIT" }, "node_modules/@mongodb-js/saslprep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.1.tgz", - "integrity": "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.6.tgz", + "integrity": "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==", "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" @@ -3134,37 +2551,85 @@ } }, "node_modules/@nestjs-modules/mailer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-2.0.2.tgz", - "integrity": "sha512-+z4mADQasg0H1ZaGu4zZTuKv2pu+XdErqx99PLFPzCDNTN/q9U59WPgkxVaHnsvKHNopLj5Xap7G4ZpptduoYw==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-2.3.4.tgz", + "integrity": "sha512-0vPNAuXGFHERFphokC5RVDgRoqwUXvI3OTPNXonw74e4QQyntp25OKzS59EaXmQOCBiIuRglmWQaFPvEpP5tuw==", + "license": "MIT", "dependencies": { - "@css-inline/css-inline": "0.14.1", - "glob": "10.3.12" + "@css-inline/css-inline": "0.20.0", + "glob": "13.0.6", + "tslib": "^2.8.1" }, "optionalDependencies": { "@types/ejs": "^3.1.5", "@types/mjml": "^4.7.4", "@types/pug": "^2.0.10", - "ejs": "^3.1.10", + "ejs": "^5.0.1", "handlebars": "^4.7.8", - "liquidjs": "^10.11.1", - "mjml": "^4.15.3", - "preview-email": "^3.0.19", - "pug": "^3.0.2" + "liquidjs": "^10.25.1", + "mjml": "^5.0.0-alpha.4", + "nunjucks": "^3.2.4", + "preview-email": "^3.1.1", + "pug": "^3.0.4" }, "peerDependencies": { "@nestjs/common": ">=7.0.9", "@nestjs/core": ">=7.0.9", + "@nestjs/event-emitter": ">=2.0.0", + "@nestjs/terminus": ">=10.0.0", "@types/ejs": ">=3.0.3", "@types/mjml": ">=4.7.4", "@types/pug": ">=2.0.6", + "bullmq": ">=4.0.0", "ejs": ">=3.1.2", "handlebars": ">=4.7.6", "liquidjs": ">=10.8.2", "mjml": ">=4.15.3", "nodemailer": ">=6.4.6", + "nunjucks": ">=3.2.0", "preview-email": ">=3.0.19", "pug": ">=3.0.1" + }, + "peerDependenciesMeta": { + "@nestjs/event-emitter": { + "optional": true + }, + "@nestjs/terminus": { + "optional": true + }, + "@types/ejs": { + "optional": true + }, + "@types/mjml": { + "optional": true + }, + "@types/pug": { + "optional": true + }, + "bullmq": { + "optional": true + }, + "ejs": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "liquidjs": { + "optional": true + }, + "mjml": { + "optional": true + }, + "nunjucks": { + "optional": true + }, + "preview-email": { + "optional": true + }, + "pug": { + "optional": true + } } }, "node_modules/@nestjs/axios": { @@ -3179,15 +2644,15 @@ } }, "node_modules/@nestjs/cli": { - "version": "11.0.16", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.16.tgz", - "integrity": "sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==", + "version": "11.0.17", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.17.tgz", + "integrity": "sha512-tOMgoB9k+Zb2WdKYPhbhceROLcDR1BFQZWfkBOGMRgBTo8rnC125E65UvThEA77vp4w+zKjqiSIv0leT+wdpHg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", - "@angular-devkit/schematics": "19.2.19", - "@angular-devkit/schematics-cli": "19.2.19", + "@angular-devkit/core": "19.2.22", + "@angular-devkit/schematics": "19.2.22", + "@angular-devkit/schematics-cli": "19.2.22", "@inquirer/prompts": "7.10.1", "@nestjs/schematics": "^11.0.1", "ansis": "4.2.0", @@ -3195,13 +2660,13 @@ "cli-table3": "0.6.5", "commander": "4.1.1", "fork-ts-checker-webpack-plugin": "9.1.0", - "glob": "13.0.0", + "glob": "13.0.6", "node-emoji": "1.11.0", "ora": "5.4.1", "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "4.2.0", "typescript": "5.9.3", - "webpack": "5.104.1", + "webpack": "5.105.4", "webpack-node-externals": "3.0.0" }, "bin": { @@ -3223,73 +2688,83 @@ } } }, - "node_modules/@nestjs/cli/node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "node_modules/@nestjs/cli/node_modules/@angular-devkit/core": { + "version": "19.2.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.22.tgz", + "integrity": "sha512-OqN/Ded+ZKypPZN5+qUFwtnKGl7FKpxJXYO2Vts5vLBojY5goCZd9SGW1CyXeuPnisRUW+vjqBQbWYuEUh36Tw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": "20 || >=22" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@nestjs/cli/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, - "node_modules/@nestjs/cli/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "node_modules/@nestjs/cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "readdirp": "^4.0.1" }, "engines": { - "node": "20 || >=22" + "node": ">= 14.16.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@nestjs/cli/node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "node_modules/@nestjs/cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/cli/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/@nestjs/common": { - "version": "11.0.13", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.0.13.tgz", - "integrity": "sha512-cXqXJPQTcJIYqT8GtBYqjYY9sklCBqp/rh9z1R40E60gWnsU598YIQWkojSFRI9G7lT/+uF+jqSrg/CMPBk7QQ==", + "version": "11.1.17", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.17.tgz", + "integrity": "sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==", + "license": "MIT", "dependencies": { + "file-type": "21.3.2", "iterare": "1.2.1", + "load-esm": "1.0.3", "tslib": "2.8.1", "uid": "2.0.2" }, @@ -3298,8 +2773,8 @@ "url": "https://opencollective.com/nest" }, "peerDependencies": { - "class-transformer": "*", - "class-validator": "*", + "class-transformer": ">=0.4.1", + "class-validator": ">=0.13.2", "reflect-metadata": "^0.1.12 || ^0.2.0", "rxjs": "^7.1.0" }, @@ -3313,13 +2788,14 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz", - "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz", + "integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==", + "license": "MIT", "dependencies": { - "dotenv": "16.4.7", - "dotenv-expand": "12.0.1", - "lodash": "4.17.21" + "dotenv": "17.2.3", + "dotenv-expand": "12.0.3", + "lodash": "4.17.23" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", @@ -3327,9 +2803,9 @@ } }, "node_modules/@nestjs/config/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -3339,21 +2815,22 @@ } }, "node_modules/@nestjs/config/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/@nestjs/core": { - "version": "11.0.13", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.0.13.tgz", - "integrity": "sha512-1xjrsYjff4sg4MfvF+/NInOq+7oI1D1vK8Yj9wkrbBH1dM+h2At71tccbFfl/eJUt4ckZlH+XmROnt/T0daYcA==", + "version": "11.1.17", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.17.tgz", + "integrity": "sha512-lD5mAYekTTurF3vDaa8C2OKPnjiz4tsfxIc5XlcSUzOhkwWf6Ay3HKvt6FmvuWQam6uIIHX52Clg+e6tAvf/cg==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "path-to-regexp": "8.2.0", + "path-to-regexp": "8.3.0", "tslib": "2.8.1", "uid": "2.0.2" }, @@ -3384,21 +2861,11 @@ } } }, - "node_modules/@nestjs/elasticsearch": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/elasticsearch/-/elasticsearch-11.1.0.tgz", - "integrity": "sha512-NwMakVs8LeXUksaSNp0ejhv223yVCK4w9iqMBrsonKj2gl4sBIBrAgJq/aXhD9bJCNLYb+waoRAsxuuPxYcjXw==", - "license": "MIT", - "peerDependencies": { - "@elastic/elasticsearch": "^7.4.0 || ^8.0.0 || ^9.0.0", - "@nestjs/common": "^10.0.0 || ^11.0.0", - "rxjs": "^7.2.0" - } - }, "node_modules/@nestjs/event-emitter": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@nestjs/event-emitter/-/event-emitter-3.0.1.tgz", "integrity": "sha512-0Ln/x+7xkU6AJFOcQI9tIhUMXVF7D5itiaQGOyJbXtlAfAIt8gzDdJm+Im7cFzKoWkiW5nCXCPh6GSvdQd/3Dw==", + "license": "MIT", "dependencies": { "eventemitter2": "6.4.9" }, @@ -3420,25 +2887,6 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" } }, - "node_modules/@nestjs/mapped-types": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", - "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", - "peerDependencies": { - "@nestjs/common": "^10.0.0 || ^11.0.0", - "class-transformer": "^0.4.0 || ^0.5.0", - "class-validator": "^0.13.0 || ^0.14.0", - "reflect-metadata": "^0.1.12 || ^0.2.0" - }, - "peerDependenciesMeta": { - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, "node_modules/@nestjs/mongoose": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-11.0.4.tgz", @@ -3455,21 +2903,22 @@ "version": "11.0.5", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", + "license": "MIT", "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" } }, "node_modules/@nestjs/platform-express": { - "version": "11.1.12", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.12.tgz", - "integrity": "sha512-GYK/vHI0SGz5m8mxr7v3Urx8b9t78Cf/dj5aJMZlGd9/1D9OI1hAl00BaphjEXINUJ/BQLxIlF2zUjrYsd6enQ==", + "version": "11.1.18", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.18.tgz", + "integrity": "sha512-s6GdHMTa3qx0fJewR74Xa30ysPHfBEqxIwZ7BGSTLoAEQ1vTP24urNl+b6+s49NFLEIOyeNho5fN/9/I17QlOw==", "license": "MIT", "dependencies": { - "cors": "2.8.5", + "cors": "2.8.6", "express": "5.2.1", - "multer": "2.0.2", - "path-to-regexp": "8.3.0", + "multer": "2.1.1", + "path-to-regexp": "8.4.2", "tslib": "2.8.1" }, "funding": { @@ -3482,9 +2931,9 @@ } }, "node_modules/@nestjs/platform-express/node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "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", @@ -3492,15 +2941,15 @@ } }, "node_modules/@nestjs/schematics": { - "version": "11.0.9", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.9.tgz", - "integrity": "sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==", + "version": "11.0.10", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.10.tgz", + "integrity": "sha512-q9lr0wGwgBHLarD4uno3XiW4JX60WPlg2VTgbqPHl/6bT4u1IEEzj+q9Tad3bVnqL5mlDF3vrZ2tj+x13CJpmw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.17", - "@angular-devkit/schematics": "19.2.17", - "comment-json": "4.4.1", + "@angular-devkit/core": "19.2.23", + "@angular-devkit/schematics": "19.2.23", + "comment-json": "4.6.2", "jsonc-parser": "3.3.1", "pluralize": "8.0.0" }, @@ -3509,16 +2958,16 @@ } }, "node_modules/@nestjs/schematics/node_modules/@angular-devkit/core": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.17.tgz", - "integrity": "sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==", + "version": "19.2.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.23.tgz", + "integrity": "sha512-RazHPQkUEsNU/OZ75w9UeHxGFMthRiuAW2B/uA7eXExBj/1meHrrBfoCA56ujW2GUxVjRtSrMjylKh4R4meiYA==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.17.1", + "ajv": "8.18.0", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", + "picomatch": "4.0.4", "rxjs": "7.8.1", "source-map": "0.7.4" }, @@ -3537,13 +2986,13 @@ } }, "node_modules/@nestjs/schematics/node_modules/@angular-devkit/schematics": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.17.tgz", - "integrity": "sha512-ADfbaBsrG8mBF6Mfs+crKA/2ykB8AJI50Cv9tKmZfwcUcyAdmTr+vVvhsBCfvUAEokigSsgqgpYxfkJVxhJYeg==", + "version": "19.2.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.23.tgz", + "integrity": "sha512-Jzs7YM4X6azmHU7Mw5tQSPMuvaqYS8SLnZOJbtiXCy1JyuW9bm/WBBecNHMiuZ8LHXKhvQ6AVX1tKrzF6uiDmw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.17", + "@angular-devkit/core": "19.2.23", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "5.4.1", @@ -3555,6 +3004,19 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@nestjs/schematics/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@nestjs/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -3566,15 +3028,15 @@ } }, "node_modules/@nestjs/swagger": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.5.tgz", - "integrity": "sha512-wCykbEybMqiYcvkyzPW4SbXKcwra9AGdajm0MvFgKR3W+gd1hfeKlo67g/s9QCRc/mqUU4KOE5Qtk7asMeFuiA==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.6.tgz", + "integrity": "sha512-oiXOxMQqDFyv1AKAqFzSo6JPvMEs4uA36Eyz/s2aloZLxUjcLfUMELSLSNQunr61xCPTpwEOShfmO7NIufKXdA==", "license": "MIT", "dependencies": { "@microsoft/tsdoc": "0.16.0", "@nestjs/mapped-types": "2.1.0", "js-yaml": "4.1.1", - "lodash": "4.17.21", + "lodash": "4.17.23", "path-to-regexp": "8.3.0", "swagger-ui-dist": "5.31.0" }, @@ -3598,26 +3060,37 @@ } } }, - "node_modules/@nestjs/swagger/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/@nestjs/swagger/node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", + "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } } }, + "node_modules/@nestjs/swagger/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, "node_modules/@nestjs/terminus": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@nestjs/terminus/-/terminus-11.0.0.tgz", - "integrity": "sha512-c55LOo9YGovmQHtFUMa/vDaxGZ2cglMTZejqgHREaApt/GArTfgYYGwhRXPLq8ZwiQQlLuYB+79e9iA8mlDSLA==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/terminus/-/terminus-11.1.1.tgz", + "integrity": "sha512-Ssql79H+EQY/Wg108eJqN4NiNsO/tLrj+qbzOWSQUf2JE4vJQ2RG3WTqUOrYjfjWmVHD3+Ys0+azed7LSMKScw==", + "license": "MIT", "dependencies": { "boxen": "5.1.2", "check-disk-space": "3.4.0" @@ -3684,9 +3157,9 @@ } }, "node_modules/@nestjs/testing": { - "version": "11.1.12", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.12.tgz", - "integrity": "sha512-W0M/i5nb9qRQpTQfJm+1mGT/+y4YezwwdcD7mxFG8JEZ5fz/ZEAk1Ayri2VBJKJUdo20B1ggnvqew4dlTMrSNg==", + "version": "11.1.18", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.18.tgz", + "integrity": "sha512-frzwNlpBgtAzI3hp/qo57DZoRO4RMTH1wST3QUYEhRTHyfPkLpzkWz3jV/mhApXjD0yT56Ptlzn6zuYPLh87Lw==", "dev": true, "license": "MIT", "dependencies": { @@ -3711,11 +3184,23 @@ } } }, + "node_modules/@nestjs/throttler": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@nestjs/throttler/-/throttler-6.5.0.tgz", + "integrity": "sha512-9j0ZRfH0QE1qyrj9JjIRDz5gQLPqq9yVC2nHsrosDVAfI5HHw08/aUAWx9DZLSdQf4HDkmhTTEGLrRFHENvchQ==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "@nestjs/core": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "reflect-metadata": "^0.1.13 || ^0.2.0" + } + }, "node_modules/@noble/hashes": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "dev": true, + "license": "MIT", "engines": { "node": "^14.21.3 || >=16" }, @@ -3727,6 +3212,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.4.1.tgz", "integrity": "sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==", + "license": "MIT", "dependencies": { "consola": "^3.2.3" }, @@ -3738,26 +3224,30 @@ "npm": ">=5.10.0" } }, - "node_modules/@one-ini/wasm": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", - "optional": true - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "node_modules/@opensearch-project/opensearch": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-3.5.1.tgz", + "integrity": "sha512-6bf+HcuERzAtHZxrm6phjref54ABse39BpkDie/YO3AUFMCBrb3SK5okKSdT5n3+nDRuEEQLhQCl0RQV3s1qpA==", "license": "Apache-2.0", + "dependencies": { + "aws4": "^1.11.0", + "debug": "^4.3.1", + "hpagent": "^1.2.0", + "json11": "^2.0.0", + "ms": "^2.1.3", + "secure-json-parse": "^2.4.0" + }, "engines": { - "node": ">=8.0.0" + "node": ">=14", + "yarn": "^1.22.10" } }, "node_modules/@paralleldrive/cuid2": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", - "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", "dev": true, + "license": "MIT", "dependencies": { "@noble/hashes": "^1.1.5" } @@ -3788,12 +3278,14 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true + "hasInstallScript": true, + "license": "Apache-2.0" }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "license": "MIT", "optional": true, "dependencies": { "domhandler": "^5.0.3", @@ -3804,9 +3296,9 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.38", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.38.tgz", - "integrity": "sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA==", + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", "dev": true, "license": "MIT" }, @@ -3815,14 +3307,15 @@ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", + "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3830,9 +3323,9 @@ } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", - "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", + "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3850,1312 +3343,907 @@ "node": ">=4" } }, - "node_modules/@smithy/abort-controller": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.5.tgz", - "integrity": "sha512-jcrqdTQurIrBbUm4W2YdLVMQDoL0sA9DTxYd2s+R/y+2U9NLOP7Xf/YqfSg1FZhlZIYEnvk2mwbyvIfdLEPo8g==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "color": "^5.0.2", + "text-hex": "1.0.x" } }, - "node_modules/@smithy/config-resolver": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.5.tgz", - "integrity": "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, - "license": "Apache-2.0", + "license": "MIT" + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@smithy/node-config-provider": "^4.3.7", - "@smithy/types": "^4.11.0", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-endpoints": "^3.2.7", - "@smithy/util-middleware": "^4.2.7", - "tslib": "^2.6.2" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" } }, - "node_modules/@smithy/core": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.8.0.tgz", - "integrity": "sha512-EYqsIYJmkR1VhVE9pccnk353xhs+lB6btdutJEtsp7R055haMJp2yE16eSxw8fv+G0WUY6vqxyYOP8kOqawxYQ==", + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", "dependencies": { - "@smithy/middleware-serde": "^4.0.9", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-stream": "^4.2.4", - "@smithy/util-utf8": "^4.0.0", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "debug": "^4.4.3", + "token-types": "^6.1.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@smithy/core/node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, - "node_modules/@smithy/core/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } + "license": "MIT" }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.7.tgz", - "integrity": "sha512-dDzrMXA8d8riFNiPvytxn0mNwR4B3h8lgrQ5UjAGu6T9z/kRg/Xncf4tEQHE/+t25sY8IH3CowcmWi+1U5B1Gw==", + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.1.4", - "@smithy/property-provider": "^4.0.5", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.1.1.tgz", - "integrity": "sha512-61WjM0PWmZJR+SnmzaKI7t7G0UkkNFboDpzIdzSoy7TByUzlxo18Qlh9s71qug4AY4hlH/CwXdubMtkcNEb/sQ==", + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.3", - "@smithy/querystring-builder": "^4.0.5", - "@smithy/types": "^4.3.2", - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/hash-node": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.5.tgz", - "integrity": "sha512-cv1HHkKhpyRb6ahD8Vcfb2Hgz67vNIXEp2vnhzfxLFGRukLCNEA5QdsorbUEzXma1Rco0u3rx5VTqbM06GcZqQ==", + "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==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, "dependencies": { - "@smithy/types": "^4.3.2", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "tslib": "^2.4.0" } }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.5.tgz", - "integrity": "sha512-IVnb78Qtf7EJpoEVo7qJ8BEXQwgC4n3igeJNNKEj/MLYtapnx8A67Zt/J3RXAj2xSO1910zk0LdFiygSemuLow==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@types/amqplib": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.8.tgz", + "integrity": "sha512-vtDp8Pk1wsE/AuQ8/Rgtm6KUZYqcnTgNvEHwzCkX8rL7AGsC6zqAfKAAJhUZXFhM/Pp++tbnUHiam/8vVpPztA==", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/node": "*" } }, - "node_modules/@smithy/is-array-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", - "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.5.tgz", - "integrity": "sha512-l1jlNZoYzoCC7p0zCtBDE5OBXZ95yMKlRlftooE5jPWQn4YBPLgsp+oeHp7iMHaTGoUdFqmHOPa8c9G3gBsRpQ==", + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@babel/types": "^7.0.0" } }, - "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.18", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.18.tgz", - "integrity": "sha512-ZhvqcVRPZxnZlokcPaTwb+r+h4yOIOCJmx0v2d1bpVlmP465g3qpVSf7wxcq5zZdu4jb0H4yIMxuPwDJSQc3MQ==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/core": "^3.8.0", - "@smithy/middleware-serde": "^4.0.9", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/shared-ini-file-loader": "^4.0.5", - "@smithy/types": "^4.3.2", - "@smithy/url-parser": "^4.0.5", - "@smithy/util-middleware": "^4.0.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@smithy/middleware-retry": { - "version": "4.1.19", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.19.tgz", - "integrity": "sha512-X58zx/NVECjeuUB6A8HBu4bhx72EoUz+T5jTMIyeNKx2lf+Gs9TmWPNNkH+5QF0COjpInP/xSpJGJ7xEnAklQQ==", + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/node-config-provider": "^4.1.4", - "@smithy/protocol-http": "^5.1.3", - "@smithy/service-error-classification": "^4.0.7", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-retry": "^4.0.7", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.0.0" + "@babel/types": "^7.28.2" } }, - "node_modules/@smithy/middleware-retry/node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@smithy/middleware-retry/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "dependencies": { + "@types/node": "*" } }, - "node_modules/@smithy/middleware-serde": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.9.tgz", - "integrity": "sha512-uAFFR4dpeoJPGz8x9mhxp+RPjo5wW0QEEIPPPbLXiRRWeCATf/Km3gKIVR5vaP8bN1kgsPhcEeh+IZvUlBv6Xg==", + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/@smithy/middleware-stack": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.5.tgz", - "integrity": "sha512-/yoHDXZPh3ocRVyeWQFvC44u8seu3eYzZRveCMfgMOBcNKnAmOvjbL9+Cp5XKSIi9iYA9PECUuW2teDAk8T+OQ==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@smithy/node-config-provider": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz", - "integrity": "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==", + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/property-provider": "^4.2.7", - "@smithy/shared-ini-file-loader": "^4.4.2", - "@smithy/types": "^4.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/node": "*" } }, - "node_modules/@smithy/node-http-handler": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.1.1.tgz", - "integrity": "sha512-RHnlHqFpoVdjSPPiYy/t40Zovf3BBHc2oemgD7VsVTFFZrU5erFFe0n52OANZZ/5sbshgD93sOh5r6I35Xmpaw==", + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.0.5", - "@smithy/protocol-http": "^5.1.3", - "@smithy/querystring-builder": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/property-provider": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.7.tgz", - "integrity": "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/protocol-http": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.3.tgz", - "integrity": "sha512-fCJd2ZR7D22XhDY0l+92pUag/7je2BztPRQ01gU5bMChcyI0rlly7QFibnYHzcxDvccMjlpM/Q1ev8ceRIb48w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@types/ejs": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", + "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==", + "license": "MIT", + "optional": true }, - "node_modules/@smithy/querystring-builder": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.5.tgz", - "integrity": "sha512-NJeSCU57piZ56c+/wY+AbAw6rxCCAOZLCIniRE7wqvndqxcKKDOXzwWjrY7wGKEISfhL9gBbAaWWgHsUGedk+A==", + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "@smithy/util-uri-escape": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/estree": "*", + "@types/json-schema": "*" } }, - "node_modules/@smithy/querystring-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.5.tgz", - "integrity": "sha512-6SV7md2CzNG/WUeTjVe6Dj8noH32r4MnUeFKZrnVYsQxpGSIcphAanQMayi8jJLZAWm6pdM9ZXvKCpWOsIGg0w==", + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/eslint": "*", + "@types/estree": "*" } }, - "node_modules/@smithy/service-error-classification": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.7.tgz", - "integrity": "sha512-XvRHOipqpwNhEjDf2L5gJowZEm5nsxC16pAZOeEcsygdjv9A2jdOh3YoDQvOXBGTsaJk6mNWtzWalOB9976Wlg==", + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz", - "integrity": "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/signature-v4": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.3.tgz", - "integrity": "sha512-mARDSXSEgllNzMw6N+mC+r1AQlEBO3meEAkR/UlfAgnMzJUB3goRBWgip1EAMG99wh36MDqzo86SfIX5Y+VEaw==", + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.5", - "@smithy/util-uri-escape": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" } }, - "node_modules/@smithy/smithy-client": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.10.tgz", - "integrity": "sha512-iW6HjXqN0oPtRS0NK/zzZ4zZeGESIFcxj2FkWed3mcK8jdSdHzvnCKXSjvewESKAgGKAbJRA+OsaqKhkdYRbQQ==", + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/core": "^3.8.0", - "@smithy/middleware-endpoint": "^4.1.18", - "@smithy/middleware-stack": "^4.0.5", - "@smithy/protocol-http": "^5.1.3", - "@smithy/types": "^4.3.2", - "@smithy/util-stream": "^4.2.4", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, - "node_modules/@smithy/types": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.11.0.tgz", - "integrity": "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==", + "node_modules/@types/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/express": "*" } }, - "node_modules/@smithy/url-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.5.tgz", - "integrity": "sha512-j+733Um7f1/DXjYhCbvNXABV53NyCRRA54C7bNEIxNPs0YjfRxeMKjjgm2jvTYrciZyCjsicHwQ6Q0ylo+NAUw==", + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.0.5", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-base64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", - "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", - "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", - "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/istanbul-lib-report": "*" } }, - "node_modules/@smithy/util-buffer-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", - "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "expect": "^30.0.0", + "pretty-format": "^30.0.0" } }, - "node_modules/@smithy/util-config-provider": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", - "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" + }, + "node_modules/@types/json-merge-patch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/json-merge-patch/-/json-merge-patch-1.0.0.tgz", + "integrity": "sha512-QYEzCCHYtwpExIOY5OWY+B3MxtoS4ekbjNrPidlJpevHqNWTJt1tAPuqgHTv+j9ufEJ+6h6nvz9zTTYwe851FA==", + "license": "MIT" }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.26", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.26.tgz", - "integrity": "sha512-xgl75aHIS/3rrGp7iTxQAOELYeyiwBu+eEgAk4xfKwJJ0L8VUjhO2shsDpeil54BOFsqmk5xfdesiewbUY5tKQ==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.5", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.26", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.26.tgz", - "integrity": "sha512-z81yyIkGiLLYVDetKTUeCZQ8x20EEzvQjrqJtb/mXnevLq2+w3XCEWTJ2pMp401b6BkEkHVfXb/cROBpVauLMQ==", + "node_modules/@types/jsonpath-plus": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonpath-plus/-/jsonpath-plus-5.0.5.tgz", + "integrity": "sha512-aaqqDf5LcGOtAfEntO5qKZS6ixT0MpNhUXNwbVPdLf7ET9hKsufJq+buZr7eXSnWoLRyGzVj2Yz2hbjVSK3wsA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^4.1.5", - "@smithy/credential-provider-imds": "^4.0.7", - "@smithy/node-config-provider": "^4.1.4", - "@smithy/property-provider": "^4.0.5", - "@smithy/smithy-client": "^4.4.10", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-endpoints": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz", - "integrity": "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg==", + "node_modules/@types/jsonschema": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/jsonschema/-/jsonschema-1.1.1.tgz", + "integrity": "sha512-JPP6H7/h/uXzAow+NbD/jqA3tA1Fj3u2C0KiFAlQ+rtl2QhozxMEz0aPjKnr4YyAB8/6s0Xm9UPa0fFUB0y1OA==", + "deprecated": "This is a stub types definition for jsonschema (https://github.com/tdegrunt/jsonschema). jsonschema provides its own type definitions, so you don't need @types/jsonschema installed!", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@smithy/node-config-provider": "^4.3.7", - "@smithy/types": "^4.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "jsonschema": "*" } }, - "node_modules/@smithy/util-hex-encoding": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", - "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/ms": "*", + "@types/node": "*" } }, - "node_modules/@smithy/util-middleware": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.7.tgz", - "integrity": "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@types/ldapjs": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-2.2.5.tgz", + "integrity": "sha512-Lv/nD6QDCmcT+V1vaTRnEKE8UgOilVv5pHcQuzkU1LcRe4mbHHuUo/KHi0LKrpdHhQY8FJzryF38fcVdeUIrzg==", + "license": "MIT", "dependencies": { - "@smithy/types": "^4.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/node": "*" } }, - "node_modules/@smithy/util-retry": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.7.tgz", - "integrity": "sha512-TTO6rt0ppK70alZpkjwy+3nQlTiqNfoXja+qwuAchIEAIoSZW8Qyd76dvBv3I5bCpE38APafG23Y/u270NspiQ==", + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^4.0.7", - "@smithy/types": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-stream": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.4.tgz", - "integrity": "sha512-vSKnvNZX2BXzl0U2RgCLOwWaAP9x/ddd/XobPK02pCbzRm5s55M53uwb1rl/Ts7RXZvdJZerPkA+en2FDghLuQ==", + "node_modules/@types/luxon": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^5.1.1", - "@smithy/node-http-handler": "^4.1.1", - "@smithy/types": "^4.3.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-uri-escape": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", - "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, - "node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@types/mjml": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.4.tgz", + "integrity": "sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@types/mjml-core": "*" } }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "node_modules/@types/mjml-core": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.15.2.tgz", + "integrity": "sha512-Q7SxFXgoX979HP57DEVsRI50TV8x1V4lfCA4Up9AvfINDM5oD/X9ARgfoyX1qS987JCnDLv85JjkqAjt3hZSiQ==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true, "license": "MIT" }, - "node_modules/@stylistic/eslint-plugin": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.7.1.tgz", - "integrity": "sha512-zjTUwIsEfT+k9BmXwq1QEFYsb4afBlsI1AXFyWQBgggMzwBFOuu92pGrE5OFx90IOjNl+lUbQoTG7f8S0PkOdg==", - "dev": true, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/types": "^8.53.1", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "estraverse": "^5.3.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=9.0.0" + "undici-types": "~7.18.0" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "dependencies": { - "tslib": "^2.8.0" + "@types/node": "*", + "form-data": "^4.0.4" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "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==", + "node_modules/@types/nodemailer": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.11.tgz", + "integrity": "sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/amqplib": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.7.tgz", - "integrity": "sha512-IVj3avf9AQd2nXCx0PGk/OYq7VmHiyNxWFSb5HhU9ATh+i+gHWvVcljFTcTWQ/dyHJCTrzCixde+r/asL2ErDA==", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@types/passport": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", + "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@types/express": "*" } }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "node_modules/@types/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0" + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@types/passport-local": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", + "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.2" + "@types/express": "*", + "@types/passport": "*" } }, - "node_modules/@types/bcrypt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", - "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/relateurl": { + "version": "0.2.33", + "resolved": "https://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.33.tgz", + "integrity": "sha512-bTQCKsVbIdzLqZhLkF5fcJQreE4y1ro4DIyVrlDNSCJRRwHhB8Z+4zXXa8jN6eDvc2HbRsEYgbvrnGvi54EpSw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/connect": "*", + "@types/http-errors": "*", "@types/node": "*" } }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" } }, - "node_modules/@types/command-line-args": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.3.tgz", - "integrity": "sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==" + "node_modules/@types/supertest": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-7.2.0.tgz", + "integrity": "sha512-uh2Lv57xvggst6lCqNdFAmDSvoMG7M/HDtX4iUCquxQ5EGPtaPM5PL5Hmi7LCvOG8db7YaCPNJEeoI8s/WzIQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } }, - "node_modules/@types/command-line-usage": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.4.tgz", - "integrity": "sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==" + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/@types/uuid": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-11.0.0.tgz", + "integrity": "sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==", + "deprecated": "This is a stub types definition. uuid provides its own type definitions, so you do not need this installed.", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "uuid": "*" } }, - "node_modules/@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "dev": true + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT" }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true - }, - "node_modules/@types/ejs": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", - "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==", - "optional": true + "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/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "@types/webidl-conversions": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "@types/yargs-parser": "*" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, "license": "MIT" }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, "license": "MIT", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", - "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "node_modules/@types/express-session": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", - "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", + "node_modules/@typescript-eslint/parser": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", "dependencies": { - "@types/express": "*" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-report": "*" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/jest": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", - "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, "license": "MIT", - "dependencies": { - "expect": "^30.0.0", - "pretty-format": "^30.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true - }, - "node_modules/@types/json-merge-patch": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/json-merge-patch/-/json-merge-patch-1.0.0.tgz", - "integrity": "sha512-QYEzCCHYtwpExIOY5OWY+B3MxtoS4ekbjNrPidlJpevHqNWTJt1tAPuqgHTv+j9ufEJ+6h6nvz9zTTYwe851FA==", - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/jsonpath-plus": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@types/jsonpath-plus/-/jsonpath-plus-5.0.5.tgz", - "integrity": "sha512-aaqqDf5LcGOtAfEntO5qKZS6ixT0MpNhUXNwbVPdLf7ET9hKsufJq+buZr7eXSnWoLRyGzVj2Yz2hbjVSK3wsA==", - "dev": true - }, - "node_modules/@types/jsonschema": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/jsonschema/-/jsonschema-1.1.1.tgz", - "integrity": "sha512-JPP6H7/h/uXzAow+NbD/jqA3tA1Fj3u2C0KiFAlQ+rtl2QhozxMEz0aPjKnr4YyAB8/6s0Xm9UPa0fFUB0y1OA==", - "deprecated": "This is a stub types definition for jsonschema (https://github.com/tdegrunt/jsonschema). jsonschema provides its own type definitions, so you don't need @types/jsonschema installed!", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, + "license": "MIT", "dependencies": { - "jsonschema": "*" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", - "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "node_modules/@typescript-eslint/types": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/ms": "*", - "@types/node": "*" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/ldapjs": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-2.2.5.tgz", - "integrity": "sha512-Lv/nD6QDCmcT+V1vaTRnEKE8UgOilVv5pHcQuzkU1LcRe4mbHHuUo/KHi0LKrpdHhQY8FJzryF38fcVdeUIrzg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@types/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, - "node_modules/@types/luxon": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", - "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/methods": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", - "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/mjml": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.4.tgz", - "integrity": "sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==", - "optional": true, + "license": "MIT", "dependencies": { - "@types/mjml-core": "*" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/@types/mjml-core": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.15.1.tgz", - "integrity": "sha512-qu8dUksU8yXX18qMTFINkM4uoz7WQYC5F14lcWeSNmWbulaGG0KG19yeZwpx75b9RJXr8WI/FRHH0LyQTU9JbA==", - "optional": true - }, - "node_modules/@types/mocha": { - "version": "10.0.10", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", - "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", - "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.13", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", - "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.4" - } - }, - "node_modules/@types/nodemailer": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.5.tgz", - "integrity": "sha512-7WtR4MFJUNN2UFy0NIowBRJswj5KXjXDhlZY43Hmots5eGu5q/dTeFd/I6GgJA/qj3RqO6dDy4SvfcV3fOVeIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@aws-sdk/client-sesv2": "^3.839.0", - "@types/node": "*" - } - }, - "node_modules/@types/passport": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", - "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/passport-jwt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", - "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", - "dev": true, - "dependencies": { - "@types/jsonwebtoken": "*", - "@types/passport-strategy": "*" - } - }, - "node_modules/@types/passport-local": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", - "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/passport": "*", - "@types/passport-strategy": "*" - } - }, - "node_modules/@types/passport-strategy": { - "version": "0.2.38", - "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", - "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/passport": "*" - } - }, - "node_modules/@types/pug": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", - "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", - "optional": true - }, - "node_modules/@types/qs": { - "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/superagent": { - "version": "8.1.9", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", - "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", - "dev": true, - "dependencies": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/supertest": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", - "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", - "dev": true, - "dependencies": { - "@types/methods": "^1.1.4", - "@types/superagent": "^8.1.0" - } - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT" - }, - "node_modules/@types/uuid": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-11.0.0.tgz", - "integrity": "sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==", - "deprecated": "This is a stub types definition. uuid provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "uuid": "*" - } - }, - "node_modules/@types/validator": { - "version": "13.15.10", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", - "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", - "license": "MIT" - }, - "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==" - }, - "node_modules/@types/whatwg-url": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", - "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz", - "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.53.1", - "@typescript-eslint/type-utils": "8.53.1", - "@typescript-eslint/utils": "8.53.1", - "@typescript-eslint/visitor-keys": "8.53.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "18 || 20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.53.1", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz", - "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.53.1", - "@typescript-eslint/types": "8.53.1", - "@typescript-eslint/typescript-estree": "8.53.1", - "@typescript-eslint/visitor-keys": "8.53.1", - "debug": "^4.4.3" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5165,20 +4253,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz", - "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.53.1", - "@typescript-eslint/types": "^8.53.1", - "debug": "^4.4.3" + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5186,210 +4273,54 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz", - "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.53.1", - "@typescript-eslint/visitor-keys": "8.53.1" - }, + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz", - "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } + "node_modules/@ucast/core": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@ucast/core/-/core-1.10.2.tgz", + "integrity": "sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==", + "license": "Apache-2.0" }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz", - "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==", - "dev": true, - "license": "MIT", + "node_modules/@ucast/js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@ucast/js/-/js-3.1.0.tgz", + "integrity": "sha512-eJ7yQeYtMK85UZjxoxBEbTWx6UMxEXKbjVyp+NlzrT5oMKV5Gpo/9bjTl3r7msaXTVC8iD9NJacqJ8yp7joX+Q==", + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "8.53.1", - "@typescript-eslint/typescript-estree": "8.53.1", - "@typescript-eslint/utils": "8.53.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz", - "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz", - "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.53.1", - "@typescript-eslint/tsconfig-utils": "8.53.1", - "@typescript-eslint/types": "8.53.1", - "@typescript-eslint/visitor-keys": "8.53.1", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz", - "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.53.1", - "@typescript-eslint/types": "8.53.1", - "@typescript-eslint/typescript-estree": "8.53.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.53.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz", - "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.53.1", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ucast/core": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@ucast/core/-/core-1.10.2.tgz", - "integrity": "sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==" - }, - "node_modules/@ucast/js": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@ucast/js/-/js-3.0.4.tgz", - "integrity": "sha512-TgG1aIaCMdcaEyckOZKQozn1hazE0w90SVdlpIJ/er8xVumE11gYAtSbw/LBeUnA4fFnFWTcw3t6reqseeH/4Q==", - "dependencies": { - "@ucast/core": "^1.0.0" + "@ucast/core": "1.10.2" } }, "node_modules/@ucast/mongo": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/@ucast/mongo/-/mongo-2.4.3.tgz", "integrity": "sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==", + "license": "Apache-2.0", "dependencies": { "@ucast/core": "^1.4.1" } }, "node_modules/@ucast/mongo2js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@ucast/mongo2js/-/mongo2js-1.4.0.tgz", - "integrity": "sha512-vR9RJ3BHlkI3RfKJIZFdVktxWvBCQRiSTeJSWN9NPxP5YJkpfXvcBWAMLwvyJx4HbB+qib5/AlSDEmQiuQyx2w==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@ucast/mongo2js/-/mongo2js-1.4.1.tgz", + "integrity": "sha512-9aeg5cmqwRQnKCXHN6I17wk83Rcm487bHelaG8T4vfpWneAI469wSI3Srnbu+PuZ5znWRbnwtVq9RgPL+bN6CA==", + "license": "Apache-2.0", "dependencies": { - "@ucast/core": "^1.6.1", - "@ucast/js": "^3.0.0", - "@ucast/mongo": "^2.4.0" + "@ucast/core": "1.10.2", + "@ucast/js": "3.1.0", + "@ucast/mongo": "2.4.3" } }, "node_modules/@ungap/structured-clone": { @@ -5698,11 +4629,25 @@ "npm": ">=8.5.0" } }, + "node_modules/@user-office-software/duo-message-broker/node_modules/amqplib": { + "version": "0.10.9", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.9.tgz", + "integrity": "sha512-jwSftI4QjS3mizvnSnOrPGYiUnm1vI2OP1iXeOUz5pb74Ua0nbf6nPyyTzuiCLEE3fMpaJORXh2K/TQ08H5xGA==", + "license": "MIT", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -5712,25 +4657,29 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -5741,13 +4690,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -5760,6 +4711,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -5769,6 +4721,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } @@ -5777,13 +4730,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -5800,6 +4755,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -5813,6 +4769,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -5825,6 +4782,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -5839,6 +4797,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -5848,23 +4807,72 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@zone-eu/mailsplit": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.8.tgz", + "integrity": "sha512-eEyACj4JZ7sjzRvy26QhLgKEMWwQbsw1+QZnlLX+/gihcNH07lVPOcnwf5U6UAL7gkc//J3jVd76o/WS+taUiA==", + "license": "(MIT OR EUPL-1.1+)", + "optional": true, + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.3.7", + "libqp": "2.1.1" + } + }, + "node_modules/@zone-eu/mailsplit/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@zone-eu/mailsplit/node_modules/libmime": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz", + "integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==", + "license": "MIT", + "optional": true, + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.6.3", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/a-sync-waterfall": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "license": "MIT", + "optional": true }, "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", - "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" @@ -5874,10 +4882,10 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -5904,15 +4912,17 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -5921,9 +4931,10 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5939,7 +4950,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -5956,7 +4967,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -5968,6 +4979,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/alce/-/alce-1.2.0.tgz", "integrity": "sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==", + "license": "MIT", "optional": true, "dependencies": { "esprima": "^1.2.0", @@ -6000,22 +5012,22 @@ } }, "node_modules/amqplib": { - "version": "0.10.9", - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.9.tgz", - "integrity": "sha512-jwSftI4QjS3mizvnSnOrPGYiUnm1vI2OP1iXeOUz5pb74Ua0nbf6nPyyTzuiCLEE3fMpaJORXh2K/TQ08H5xGA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-1.0.3.tgz", + "integrity": "sha512-nsrXa59tvX4HPjPPW8JJGuBb/Db0MOq3DOhGdSbIY7bTsQDMV2fmF9c3i74g/8Gt9+QWyrxfEPppOOoV9lK1uQ==", "license": "MIT", "dependencies": { - "buffer-more-ints": "~1.0.0", - "url-parse": "~1.5.10" + "buffer-more-ints": "~1.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", "dependencies": { "string-width": "^4.1.0" } @@ -6025,6 +5037,7 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6034,6 +5047,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -6044,10 +5058,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -6056,6 +5084,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6081,6 +5110,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "devOptional": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6090,10 +5120,11 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -6101,38 +5132,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/apache-arrow": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-18.1.0.tgz", - "integrity": "sha512-v/ShMp57iBnBp4lDgV8Jx3d3Q5/Hac25FWmQ98eMahUiHPXcvwIMKJD0hBIgclm/FCG+LwPkAKtkRO1O/W0YGg==", - "dependencies": { - "@swc/helpers": "^0.5.11", - "@types/command-line-args": "^5.2.3", - "@types/command-line-usage": "^5.0.4", - "@types/node": "^20.13.0", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.1", - "flatbuffers": "^24.3.25", - "json-bignum": "^0.0.3", - "tslib": "^2.6.2" - }, - "bin": { - "arrow2csv": "bin/arrow2csv.js" - } - }, - "node_modules/apache-arrow/node_modules/@types/node": { - "version": "20.17.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.30.tgz", - "integrity": "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/apache-arrow/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" - }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -6143,20 +5142,14 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "engines": { - "node": ">=6" - } + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/array-timsort": { "version": "1.0.3", @@ -6169,12 +5162,14 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } @@ -6195,12 +5190,14 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "license": "MIT", "optional": true }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", "engines": { "node": ">=0.8" } @@ -6218,35 +5215,43 @@ "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, - "node_modules/axios": { + "node_modules/aws4": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", - "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", + "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "30.2.0", + "@jest/transform": "30.3.0", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.2.0", + "babel-preset-jest": "30.3.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -6279,9 +5284,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", - "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", + "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", "dev": true, "license": "MIT", "dependencies": { @@ -6319,13 +5324,13 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", - "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", + "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.2.0", + "babel-plugin-jest-hoist": "30.3.0", "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { @@ -6339,6 +5344,7 @@ "version": "3.0.0-canary-5", "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "license": "MIT", "optional": true, "dependencies": { "@babel/types": "^7.9.6" @@ -6351,6 +5357,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", "integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==", + "license": "MIT", "dependencies": { "precond": "0.2" }, @@ -6361,7 +5368,9 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -6381,16 +5390,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz", - "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==", - "dev": true, + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "devOptional": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/bcrypt": { @@ -6410,12 +5423,14 @@ "node_modules/bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -6429,6 +5444,7 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6436,15 +5452,15 @@ } }, "node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "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", @@ -6453,7 +5469,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -6465,39 +5481,18 @@ "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC", "optional": true }, - "node_modules/bowser": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.1.tgz", - "integrity": "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==", - "dev": true, - "license": "MIT" - }, "node_modules/boxen": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "license": "MIT", "dependencies": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", @@ -6515,32 +5510,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boxen/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/boxen/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -6554,10 +5528,10 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "devOptional": true, + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6569,6 +5543,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "devOptional": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -6580,13 +5555,14 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -6601,6 +5577,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -6620,6 +5597,7 @@ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -6632,6 +5610,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -6664,6 +5643,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -6678,12 +5658,14 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, "node_modules/buffer-more-ints": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", - "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==", + "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", @@ -6709,6 +5691,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -6721,6 +5704,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -6736,25 +5720,17 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", - "optional": true, - "dependencies": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -6762,11 +5738,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "optional": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001760", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", - "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", - "dev": true, + "version": "1.0.30001781", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -6816,6 +5805,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6827,20 +5817,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", - "dependencies": { - "chalk": "^4.1.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" - } - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -6855,6 +5831,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "license": "MIT", "optional": true, "dependencies": { "is-regex": "^1.0.3" @@ -6872,6 +5849,7 @@ "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -6880,26 +5858,32 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz", "integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==", + "license": "MIT", "engines": { "node": ">=16" } }, "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "license": "MIT", "optional": true, "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=18.17" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -6909,6 +5893,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { "boolbase": "^1.0.0", @@ -6923,18 +5908,41 @@ } }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "optional": true, "dependencies": { - "readdirp": "^4.0.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/chrome-trace-event": { @@ -6942,73 +5950,56 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/sibiraj-s" } ], - "optional": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", - "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "dev": true, "license": "MIT" }, "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" }, "node_modules/class-validator": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", - "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.15.1.tgz", + "integrity": "sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==", "license": "MIT", "dependencies": { "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", - "validator": "^13.15.20" - } - }, - "node_modules/clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", - "optional": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "engines": { - "node": ">=0.10.0" + "validator": "^13.15.22" } }, "node_modules/cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "license": "MIT", "engines": { "node": ">=6" }, @@ -7021,6 +6012,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7033,6 +6025,7 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -7044,6 +6037,7 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", "dependencies": { "string-width": "^4.2.0" }, @@ -7069,6 +6063,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "devOptional": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -7078,23 +6073,12 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "devOptional": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7112,6 +6096,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -7121,6 +6106,7 @@ "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-3.0.0.tgz", "integrity": "sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==", "dev": true, + "license": "MIT", "dependencies": { "is-regexp": "^3.0.0" }, @@ -7143,26 +6129,30 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, "license": "MIT" }, "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", "license": "MIT", "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" } }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7173,47 +6163,63 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" } }, "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" } }, "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" + "engines": { + "node": ">=12.20" } }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT", + "optional": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7221,68 +6227,24 @@ "node": ">= 0.8" } }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", - "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", - "dependencies": { - "array-back": "^6.2.2", - "chalk-template": "^0.4.0", - "table-layout": "^4.1.0", - "typical": "^7.1.1" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", - "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", - "engines": { - "node": ">=12.17" - } - }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/comment-json": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.4.1.tgz", - "integrity": "sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz", + "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==", "dev": true, "license": "MIT", "dependencies": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.3", "esprima": "^4.0.1" }, "engines": { @@ -7290,9 +6252,10 @@ } }, "node_modules/complex.js": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.2.tgz", - "integrity": "sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.3.tgz", + "integrity": "sha512-UrQVSUur14tNX6tiP4y8T4w4FeJAX3bi2cIv0pu/DTLFNxoq7z2Yh83Vfzztj6Px3X/lubqQ9IrPp7Bpn6p4MQ==", + "license": "MIT", "engines": { "node": "*" }, @@ -7306,6 +6269,7 @@ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -7314,7 +6278,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true + "dev": true, + "license": "MIT" }, "node_modules/concat-stream": { "version": "2.0.0", @@ -7361,6 +6326,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7371,16 +6337,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "optional": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "node_modules/connect-mongo": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-6.0.0.tgz", @@ -7402,6 +6358,7 @@ "version": "3.4.2", "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -7410,6 +6367,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "license": "MIT", "optional": true, "dependencies": { "@babel/parser": "^7.6.0", @@ -7417,20 +6375,23 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dependencies": { - "safe-buffer": "5.2.1" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7440,6 +6401,7 @@ "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -7451,12 +6413,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7465,6 +6429,7 @@ "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" } @@ -7473,25 +6438,24 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, "license": "MIT" }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cosmiconfig": { @@ -7499,6 +6463,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -7524,12 +6489,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "devOptional": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7539,10 +6507,24 @@ "node": ">= 8" } }, + "node_modules/css-declaration-sorter": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.1.tgz", + "integrity": "sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==", + "license": "ISC", + "optional": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { "boolbase": "^1.0.0", @@ -7555,10 +6537,25 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "optional": true, + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", "optional": true, "engines": { "node": ">= 6" @@ -7567,10 +6564,158 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "optional": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.3.tgz", + "integrity": "sha512-mLFHQAzyapMVFLiJIn7Ef4C2UCEvtlTlbyILR6B5ZsUAV3D/Pa761R5uC1YPhyBkRd3eqaDm2ncaNrD7R4mTRg==", + "license": "MIT", + "optional": true, + "dependencies": { + "cssnano-preset-default": "^7.0.11", + "lilconfig": "^3.1.3" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/cssnano-preset-default": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.11.tgz", + "integrity": "sha512-waWlAMuCakP7//UCY+JPrQS1z0OSLeOXk2sKWJximKWGupVxre50bzPlvpbUwZIDylhf/ptf0Pk+Yf7C+hoa3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "browserslist": "^4.28.1", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^5.0.1", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^7.0.6", + "postcss-convert-values": "^7.0.9", + "postcss-discard-comments": "^7.0.6", + "postcss-discard-duplicates": "^7.0.2", + "postcss-discard-empty": "^7.0.1", + "postcss-discard-overridden": "^7.0.1", + "postcss-merge-longhand": "^7.0.5", + "postcss-merge-rules": "^7.0.8", + "postcss-minify-font-values": "^7.0.1", + "postcss-minify-gradients": "^7.0.1", + "postcss-minify-params": "^7.0.6", + "postcss-minify-selectors": "^7.0.6", + "postcss-normalize-charset": "^7.0.1", + "postcss-normalize-display-values": "^7.0.1", + "postcss-normalize-positions": "^7.0.1", + "postcss-normalize-repeat-style": "^7.0.1", + "postcss-normalize-string": "^7.0.1", + "postcss-normalize-timing-functions": "^7.0.1", + "postcss-normalize-unicode": "^7.0.6", + "postcss-normalize-url": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1", + "postcss-ordered-values": "^7.0.2", + "postcss-reduce-initial": "^7.0.6", + "postcss-reduce-transforms": "^7.0.1", + "postcss-svgo": "^7.1.1", + "postcss-unique-selectors": "^7.0.5" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/cssnano-preset-lite": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/cssnano-preset-lite/-/cssnano-preset-lite-4.0.4.tgz", + "integrity": "sha512-iV7xT9JEk0OJwRWuSV2Y48IkntNjvoiscoioFDcgmuoIvpZV8gIg1++GBHTj72HgmDCALH8y9ELgt+aFM2Nh9g==", + "license": "MIT", + "optional": true, + "dependencies": { + "cssnano-utils": "^5.0.1", + "postcss-discard-comments": "^7.0.4", + "postcss-discard-empty": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/cssnano-utils": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", + "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "optional": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0", + "optional": true + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", "engines": { "node": ">= 12" } @@ -7597,6 +6742,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7605,14 +6751,15 @@ } }, "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==" + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" }, "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -7628,6 +6775,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "optional": true, "engines": { "node": ">=4.0.0" @@ -7637,13 +6785,15 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7653,6 +6803,7 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -7664,6 +6815,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -7672,6 +6824,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7680,6 +6833,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -7690,6 +6844,7 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7698,6 +6853,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT", "optional": true }, "node_modules/dezalgo": { @@ -7705,6 +6861,7 @@ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, + "license": "ISC", "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -7731,28 +6888,34 @@ } }, "node_modules/display-notification": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/display-notification/-/display-notification-2.0.0.tgz", - "integrity": "sha512-TdmtlAcdqy1NU+j7zlkDdMnCL878zriLaBmoD9quOoq1ySSSGv03l0hXK5CvIFZlIfFI/hizqdQuW+Num7xuhw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/display-notification/-/display-notification-3.0.0.tgz", + "integrity": "sha512-/qAvqRy4zWP847zJc1GvXOc+AV1l9/ECKPA7APrLnqjur0o5liMM4bDJ/b1hnJo6Tyb5BfOHyyd4vn9lCh/NSg==", + "license": "MIT", "optional": true, "dependencies": { - "escape-string-applescript": "^1.0.0", - "run-applescript": "^3.0.0" + "escape-string-applescript": "^3.0.0", + "run-applescript": "^5.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "license": "MIT", "optional": true }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", "optional": true, "dependencies": { "domelementtype": "^2.3.0", @@ -7773,12 +6936,14 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "BSD-2-Clause", "optional": true }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { "domelementtype": "^2.3.0" @@ -7794,6 +6959,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { "dom-serializer": "^2.0.0", @@ -7805,9 +6971,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", + "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -7833,9 +6999,10 @@ } }, "node_modules/dotenv-expand": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.1.tgz", - "integrity": "sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "license": "BSD-2-Clause", "dependencies": { "dotenv": "^16.4.5" }, @@ -7862,6 +7029,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -7874,7 +7042,9 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "devOptional": true, + "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", @@ -7885,83 +7055,30 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", - "optional": true, - "dependencies": { - "@one-ini/wasm": "0.1.1", - "commander": "^10.0.0", - "minimatch": "9.0.1", - "semver": "^7.5.3" - }, - "bin": { - "editorconfig": "bin/editorconfig" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/editorconfig/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "optional": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz", + "integrity": "sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==", + "license": "Apache-2.0", "optional": true, - "dependencies": { - "jake": "^10.8.5" - }, "bin": { "ejs": "bin/cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.18" } }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, + "version": "1.5.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.322.tgz", + "integrity": "sha512-vFU34OcrvMcH66T+dYC3G4nURmgfDVewMIu6Q2urXpumAPSMmzvcn04KVVV8Opikq8Vs5nUbO/8laNhNRqSzYw==", + "devOptional": true, "license": "ISC" }, "node_modules/emittery": { @@ -7980,7 +7097,8 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/enabled": { "version": "2.0.0", @@ -7992,6 +7110,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8000,19 +7119,48 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", + "license": "MIT", "optional": true, "engines": { "node": ">=8.10.0" } }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/enhanced-resolve": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", - "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "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.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -8022,6 +7170,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "optional": true, "engines": { "node": ">=0.12" @@ -8030,11 +7179,22 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "devOptional": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } @@ -8043,6 +7203,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -8051,6 +7212,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -8066,6 +7228,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -8077,6 +7240,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -8092,6 +7256,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8100,6 +7265,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "license": "MIT", "optional": true, "engines": { "node": ">=10" @@ -8111,20 +7277,26 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-latex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", - "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", + "license": "MIT" }, "node_modules/escape-string-applescript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-1.0.0.tgz", - "integrity": "sha512-4/hFwoYaC6TkpDn9A3pTC52zQPArFeXuIfhUtCGYdauTzXVP9H3BDr3oO/QzQehMpLDC7srvYgfwvImPFGfvBA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-3.0.0.tgz", + "integrity": "sha512-Wru0bY9XSICPNsy7KwbAZww9SLkoYjP9GtJkmnQOEqOy9U13KA0OJXoti7FaVMsiQ0mQfh916/xoByM6PqdW4g==", + "license": "MIT", "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/escape-string-regexp": { @@ -8132,6 +7304,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -8140,33 +7313,30 @@ } }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", + "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -8176,8 +7346,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -8185,937 +7354,1662 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "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", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-session": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz", + "integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==", + "license": "MIT", + "dependencies": { + "cookie": "~0.7.2", + "cookie-signature": "~1.0.7", + "debug": "~2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.1.0", + "parseurl": "~1.3.3", + "safe-buffer": "~5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-session/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" + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/extend-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", + "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==", + "license": "MIT", + "optional": true + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-type": { + "version": "21.3.2", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.2.tgz", + "integrity": "sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "devOptional": true, "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" + "dependencies": { + "to-regex-range": "^5.0.1" }, - "peerDependencies": { - "eslint": ">=7.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", - "dev": true, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" + "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": "^14.18.0 || >=16.0.0" + "node": ">= 18.0.0" }, "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/fixpack": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-4.0.0.tgz", + "integrity": "sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "alce": "1.2.0", + "chalk": "^3.0.0", + "detect-indent": "^6.0.0", + "detect-newline": "^3.1.0", + "extend-object": "^1.0.0", + "rc": "^1.2.8" }, - "funding": { - "url": "https://opencollective.com/eslint" + "bin": { + "fixpack": "bin/fixpack" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "node_modules/fixpack/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "optional": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=8" } }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=16" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "devOptional": true, + "license": "ISC", "dependencies": { - "estraverse": "^5.1.0" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=0.10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^4.0.1", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" }, "engines": { - "node": ">=4.0" + "node": ">=14.21.3" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, "engines": { - "node": ">=4.0" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, "engines": { - "node": ">= 0.6" + "node": ">= 6" } }, - "node_modules/eventemitter2": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { - "node": ">=0.8.x" + "node": ">= 0.6" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "mime-db": "1.52.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">= 0.6" } }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/exit-x": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", - "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", - "dev": true, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=12.20.0" } }, - "node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "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", - "url": "https://opencollective.com/express" + "node": ">= 0.6" } }, - "node_modules/express-session": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz", - "integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==", + "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==", "license": "MIT", - "dependencies": { - "cookie": "~0.7.2", - "cookie-signature": "~1.0.7", - "debug": "~2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.1.0", - "parseurl": "~1.3.3", - "safe-buffer": "~5.2.1", - "uid-safe": "~2.1.5" - }, "engines": { - "node": ">= 0.8.0" + "node": "*" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "type": "github", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/express-session/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==" + "node_modules/fresh": { + "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.8" + } }, - "node_modules/express-session/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/express-session/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/fs-monkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" }, - "node_modules/extend-object": { + "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", - "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==", - "optional": true + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" }, - "node_modules/extsprintf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", - "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", - "engines": [ - "node >=0.6.0" - ] + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "node_modules/function-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-0.1.1.tgz", + "integrity": "sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/gelf-pro": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gelf-pro/-/gelf-pro-1.4.0.tgz", + "integrity": "sha512-VXQ1DHQjQr8/Xil83hHgozqeCcVrggGAA6A8hgjojQSatiF6PErR+nnYv/DCBxFBolO6licomD7Abaj0Iec7Qg==", + "license": "MIT", + "dependencies": { + "lodash": "~4.17.21" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "node_modules/gelf-pro/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ] + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "node_modules/fast-xml-parser": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", - "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "strnum": "^2.1.0" + "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" }, - "bin": { - "fxparser": "src/cli/cli.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "dependencies": { - "bser": "2.1.1" + "license": "MIT", + "engines": { + "node": ">=8.0.0" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "license": "MIT", + "optional": true, "engines": { - "node": ">=12.0.0" + "node": ">=8" }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "engines": { + "node": ">= 0.4" } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "flat-cache": "^4.0.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.13.0" } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "optional": true, - "dependencies": { - "minimatch": "^5.0.1" + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "license": "MIT", - "optional": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "node_modules/globals": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/filenamify": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", - "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", - "dev": true, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.1", - "trim-repeated": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "devOptional": true, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">=8" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dependencies": { - "array-back": "^3.0.1" - }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">=8" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fixpack": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-4.0.0.tgz", - "integrity": "sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==", - "optional": true, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "alce": "1.2.0", - "chalk": "^3.0.0", - "detect-indent": "^6.0.0", - "detect-newline": "^3.1.0", - "extend-object": "^1.0.0", - "rc": "^1.2.8" + "has-symbols": "^1.0.3" }, - "bin": { - "fixpack": "bin/fixpack" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fixpack/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "optional": true, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "devOptional": true, + "license": "MIT", "bin": { - "flat": "cli.js" + "he": "bin/he" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, + "license": "MIT" + }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "license": "MIT", + "optional": true, "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" }, "engines": { - "node": ">=16" + "node": ">=14" } }, - "node_modules/flatbuffers": { - "version": "24.12.23", - "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.12.23.tgz", - "integrity": "sha512-dLVCAISd5mhls514keQzmEG6QHmUUsNuWsb4tFafIUwvvgDjXhtfAYSKOzt5SWOy+qByV5pbsDZ+Vb7HUOBEdA==" - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT" - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "node_modules/html-to-text/node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" + "type": "github", + "url": "https://github.com/sponsors/fb55" } ], - "engines": { - "node": ">=4.0" + "license": "MIT", + "optional": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/htmlnano": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-3.2.0.tgz", + "integrity": "sha512-ZUCyB3w9EdpkaePGuYTBF7hT1MWdcz7y0/h2Cnl1MKLwbyj7aIM+Eq7SRg+ILF1mvR7zJKu06lw9zpgCxOFymw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/relateurl": "^0.2.33", + "commander": "^14.0.0", + "cosmiconfig": "^9.0.0", + "posthtml": "^0.16.5" + }, + "bin": { + "htmlnano": "dist/bin.js" + }, + "peerDependencies": { + "cssnano": "^7.0.0", + "postcss": "^8.3.11", + "purgecss": "^8.0.0", + "relateurl": "^0.2.7", + "srcset": "^5.0.1", + "svgo": "^4.0.0", + "terser": "^5.21.0", + "uncss": "^0.17.3" }, "peerDependenciesMeta": { - "debug": { + "cssnano": { + "optional": true + }, + "postcss": { + "optional": true + }, + "purgecss": { + "optional": true + }, + "relateurl": { + "optional": true + }, + "srcset": { + "optional": true + }, + "svgo": { + "optional": true + }, + "terser": { + "optional": true + }, + "uncss": { "optional": true } } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "node_modules/htmlnano/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + } + }, + "node_modules/htmlnano/node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "license": "MIT", + "optional": true, "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/fork-ts-checker-webpack-plugin": { + "node_modules/htmlparser2": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz", - "integrity": "sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==", - "dev": true, + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "optional": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^4.0.1", - "cosmiconfig": "^8.2.0", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=14.21.3" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" } }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/form-data/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==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "devOptional": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.6" + "node": ">=10.17.0" } }, - "node_modules/form-data/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==", + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12.20.0" + "node": ">= 4" } }, - "node_modules/formidable": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", - "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", - "dev": true, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@paralleldrive/cuid2": "^2.2.2", - "dezalgo": "^1.0.4", - "once": "^1.4.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=6" }, "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fraction.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.2.2.tgz", - "integrity": "sha512-uXBDv5knpYmv/2gLzWQ5mBHGBRk9wcKTeWu6GLTUEQfjCxO09uM/mHDrojlL+Q1mVGIIFo149Gba7od1XPgSzQ==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, "engines": { - "node": ">= 12" + "node": ">=8" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.8.19" } }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC", + "optional": true }, - "node_modules/function-timeout": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-0.1.1.tgz", - "integrity": "sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==", + "node_modules/ip-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", + "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=14.16" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gelf-pro": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gelf-pro/-/gelf-pro-1.4.0.tgz", - "integrity": "sha512-VXQ1DHQjQr8/Xil83hHgozqeCcVrggGAA6A8hgjojQSatiF6PErR+nnYv/DCBxFBolO6licomD7Abaj0Iec7Qg==", - "dependencies": { - "lodash": "~4.17.21" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 0.10" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "devOptional": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "optional": true, "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" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9124,21 +9018,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "optional": true, + "bin": { + "is-docker": "cli.js" + }, "engines": { "node": ">=8" }, @@ -9146,4096 +9034,4496 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "license": "MIT", + "optional": true, "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "optional": true, + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">= 0.4" + "node": ">=0.4.0" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=0.10.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/is-ip": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-5.0.1.tgz", + "integrity": "sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "ip-regex": "^5.0.0", + "super-regex": "^0.2.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz", - "integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==", + "node_modules/is-json": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", + "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", + "license": "ISC", + "optional": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT", + "optional": true }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "optional": true, "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=0.4.7" + "node": ">= 0.4" }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-regexp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", + "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "optional": true, "dependencies": { - "function-bind": "^1.1.2" + "is-docker": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true, - "bin": { - "he": "bin/he" - } + "license": "ISC" }, - "node_modules/hpagent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", - "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", - "license": "MIT", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=14" + "node": ">=8" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "MIT" - }, - "node_modules/html-minifier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", - "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", - "optional": true, + "license": "BSD-3-Clause", "dependencies": { - "camel-case": "^3.0.0", - "clean-css": "^4.2.1", - "commander": "^2.19.0", - "he": "^1.2.0", - "param-case": "^2.1.1", - "relateurl": "^0.2.7", - "uglify-js": "^3.5.1" - }, - "bin": { - "html-minifier": "cli.js" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/html-minifier/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, - "node_modules/html-to-text": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", - "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", - "optional": true, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@selderee/plugin-htmlparser2": "^0.11.0", - "deepmerge": "^4.3.1", - "dom-serializer": "^2.0.0", - "htmlparser2": "^8.0.2", - "selderee": "^0.11.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=14" + "node": ">=10" } }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "optional": true, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" + } + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "devOptional": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "license": "MIT" + }, + "node_modules/jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", + "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@jest/core": "30.3.0", + "@jest/types": "30.3.0", + "import-local": "^3.2.0", + "jest-cli": "30.3.0" + }, + "bin": { + "jest": "bin/jest.js" + }, "engines": { - "node": ">=10.17.0" + "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 + } } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, + "node_modules/jest-changed-files": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", + "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", + "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "execa": "^5.1.1", + "jest-util": "30.3.0", + "p-limit": "^3.1.0" }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/jest-circus": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", + "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "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.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, "engines": { - "node": ">= 4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/jest-cli": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", + "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@jest/core": "30.3.0", + "@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", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "node_modules/jest-config": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", + "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", "dev": true, "license": "MIT", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "@babel/core": "^7.27.4", + "@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", + "chalk": "^4.1.2", + "ci-info": "^4.2.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" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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 + } } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, - "engines": { - "node": ">=0.8.19" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "node_modules/jest-config/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "optional": true + "node_modules/jest-config/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" }, - "node_modules/ip-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", - "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/jest-config/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">= 0.10" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "optional": true, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "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==", - "optional": true, + "node_modules/jest-diff/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "optional": true, - "bin": { - "is-docker": "cli.js" - }, + "node_modules/jest-diff/node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-expression": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", - "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", - "optional": true, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^7.1.1", - "object-assign": "^4.1.1" - } - }, - "node_modules/is-expression/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "optional": true, - "bin": { - "acorn": "bin/acorn" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=0.4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-each": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", + "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", + "dev": true, + "license": "MIT", + "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" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "node_modules/jest-environment-node": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", + "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0" + }, "engines": { - "node": ">=6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "node_modules/jest-file-snapshot": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/jest-file-snapshot/-/jest-file-snapshot-0.7.0.tgz", + "integrity": "sha512-HkuzLleG2bEVz5nu7ey3SkiBeBvTz8IhY0mJ9W+9BO4xiIi3nVUfB81jFLWS7PMPpeBVgkpW0G1YyrYKi3Hcxw==", + "dev": true, + "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "chalk": "^4.1.2", + "filenamify": "^4.3.0", + "jest-diff": "^29.7.0", + "mkdirp": "^3.0.1" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-ip": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-5.0.1.tgz", - "integrity": "sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==", + "node_modules/jest-haste-map": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", + "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", "dev": true, + "license": "MIT", "dependencies": { - "ip-regex": "^5.0.0", - "super-regex": "^0.2.0" + "@jest/types": "30.3.0", + "@types/node": "*", + "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.3", + "walker": "^1.0.8" }, "engines": { - "node": ">=14.16" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/jest-leak-detector": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", + "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.3.0" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "optional": true - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "optional": true, + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-regexp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", - "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" + "node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "optional": true, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", + "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", + "dev": true, + "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/jest-resolve-dependencies": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", + "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.3.0" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "node_modules/jest-runner": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", + "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" + "@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": "*", + "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" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/jest-runtime": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", + "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "@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": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "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" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=8" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/iterare": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", - "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", - "engines": { - "node": ">=6" - } + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=14" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "optional": true, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" - }, - "node_modules/jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", - "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "node_modules/jest-snapshot": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", + "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/types": "30.2.0", - "import-local": "^3.2.0", - "jest-cli": "30.2.0" - }, - "bin": { - "jest": "bin/jest.js" + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@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", + "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.2", + "synckit": "^0.11.8" }, "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 - } } }, - "node_modules/jest-changed-files": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", - "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", "dev": true, "license": "MIT", "dependencies": { - "execa": "^5.1.1", - "jest-util": "30.2.0", - "p-limit": "^3.1.0" + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-circus": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", - "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", + "@jest/types": "30.3.0", "@types/node": "*", "chalk": "^4.1.2", - "co": "^4.6.0", - "dedent": "^1.6.0", - "is-generator-fn": "^2.1.0", - "jest-each": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "p-limit": "^3.1.0", - "pretty-format": "30.2.0", - "pure-rand": "^7.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-cli": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", - "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", "chalk": "^4.1.2", - "exit-x": "^0.2.2", - "import-local": "^3.2.0", - "jest-config": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "yargs": "^17.7.2" - }, - "bin": { - "jest": "bin/jest.js" + "leven": "^3.1.0", + "pretty-format": "30.3.0" }, "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 - } } }, - "node_modules/jest-config": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", - "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "node_modules/jest-watcher": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", + "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.2.0", - "@jest/types": "30.2.0", - "babel-jest": "30.2.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "deepmerge": "^4.3.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-circus": "30.2.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-runner": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "micromatch": "^4.0.8", - "parse-json": "^5.2.0", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "emittery": "^0.13.1", + "jest-util": "30.3.0", + "string-length": "^4.0.2" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { + } + }, + "node_modules/jest-worker": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", + "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", + "dev": true, + "license": "MIT", + "dependencies": { "@types/node": "*", - "esbuild-register": ">=3.4.0", - "ts-node": ">=9.0.0" + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.3.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esbuild-register": { - "optional": true - }, - "ts-node": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-config/node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.1.1.tgz", + "integrity": "sha512-pJkBiPtNo+o0h19LfSvUN46Y5zY+ck99AtHwch9n2HqVLNRgP0ZMyIH8FRMoP+HV8hy/+AG99dXFfwpf83iZfQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/address": "^5.1.1", + "@hapi/formula": "^3.0.2", + "@hapi/hoek": "^11.0.7", + "@hapi/pinpoint": "^2.0.1", + "@hapi/tlds": "^1.1.1", + "@hapi/topo": "^6.0.2", + "@standard-schema/spec": "^1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/jose": { + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "license": "MIT", + "optional": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.2.0" + "argparse": "^2.0.1" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jest-docblock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", - "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", - "dev": true, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", "license": "MIT", - "dependencies": { - "detect-newline": "^3.1.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 10.16.0" } }, - "node_modules/jest-each": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", - "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "jest-util": "30.2.0", - "pretty-format": "30.2.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=6" } }, - "node_modules/jest-environment-node": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", - "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, + "license": "MIT" + }, + "node_modules/json-merge-patch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-1.0.2.tgz", + "integrity": "sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==", "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "fast-deep-equal": "^3.1.3" } }, - "node_modules/jest-file-snapshot": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/jest-file-snapshot/-/jest-file-snapshot-0.7.0.tgz", - "integrity": "sha512-HkuzLleG2bEVz5nu7ey3SkiBeBvTz8IhY0mJ9W+9BO4xiIi3nVUfB81jFLWS7PMPpeBVgkpW0G1YyrYKi3Hcxw==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, + "license": "MIT" + }, + "node_modules/json11": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/json11/-/json11-2.0.2.tgz", + "integrity": "sha512-HIrd50UPYmP6sqLuLbFVm75g16o0oZrVfxrsY0EEys22klz8mRoWlX9KAEDOSOR9Q34rcxsyC8oDveGrCz5uLQ==", "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "filenamify": "^4.3.0", - "jest-diff": "^29.7.0", - "mkdirp": "^3.0.1" + "bin": { + "json11": "dist/cli.mjs" } }, - "node_modules/jest-file-snapshot/node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" + "bin": { + "json5": "lib/cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6" } }, - "node_modules/jest-file-snapshot/node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "dev": true, "license": "MIT" }, - "node_modules/jest-file-snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "universalify": "^2.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/jest-file-snapshot/node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-file-snapshot/node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true, - "license": "MIT", "bin": { - "mkdirp": "dist/cjs/src/bin.js" + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18.0.0" } }, - "node_modules/jest-file-snapshot/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "*" } }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", + "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.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12", + "npm": ">=6" } }, - "node_modules/jest-haste-map": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", - "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", - "dev": true, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "license": "MIT", + "optional": true, "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "anymatch": "^3.1.3", - "fb-watchman": "^2.0.2", - "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "micromatch": "^4.0.8", - "walker": "^1.0.8" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.3" + "is-promise": "^2.0.0", + "promise": "^7.0.1" } }, - "node_modules/jest-leak-detector": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", - "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", - "dev": true, + "node_modules/juice": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/juice/-/juice-11.1.1.tgz", + "integrity": "sha512-4SBfZqKcc6DrIS+5b/WiGoWaZsdUPBH+e6SbRlNjJpaIRtfoBhYReAtobIEW6mcLeFFDXLBJMuZwkJLkBJjs2w==", "license": "MIT", + "optional": true, "dependencies": { - "@jest/get-type": "30.1.0", - "pretty-format": "30.2.0" + "cheerio": "1.0.0", + "commander": "^12.1.0", + "entities": "^7.0.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^8.0.0" + }, + "bin": { + "juice": "bin/juice" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.17" } }, - "node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, + "node_modules/juice/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" - }, + "optional": true, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18" } }, - "node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, + "node_modules/juice/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "optional": true, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, - "license": "MIT", + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=12.0.0" } }, - "node_modules/jest-resolve": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", - "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "slash": "^3.0.0", - "unrs-resolver": "^1.7.11" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "json-buffer": "3.0.1" } }, - "node_modules/jest-resolve-dependencies": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", - "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", - "dev": true, + "node_modules/kruptein": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.8.tgz", + "integrity": "sha512-0CyalFA0Cjp3jnziMp0u1uLZW2/ouhQ0mEMfYlroBXNe86na1RwAuwBcdRAegeWZNMfQy/G5fN47g/Axjtqrfw==", "license": "MIT", "dependencies": { - "jest-regex-util": "30.0.1", - "jest-snapshot": "30.2.0" + "asn1.js": "^5.4.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">8" } }, - "node_modules/jest-runner": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", - "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", - "dev": true, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/ldap-filter": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz", + "integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==", "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", - "@jest/environment": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "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.2.0", - "jest-haste-map": "30.2.0", - "jest-leak-detector": "30.2.0", - "jest-message-util": "30.2.0", - "jest-resolve": "30.2.0", - "jest-runtime": "30.2.0", - "jest-util": "30.2.0", - "jest-watcher": "30.2.0", - "jest-worker": "30.2.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "assert-plus": "^1.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.8" } }, - "node_modules/jest-runtime": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", - "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", - "dev": true, + "node_modules/ldapauth-fork": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-5.0.5.tgz", + "integrity": "sha512-LWUk76+V4AOZbny/3HIPQtGPWZyA3SW2tRhsWIBi9imP22WJktKLHV1ofd8Jo/wY7Ve6vAT7FCI5mEn3blZTjw==", "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/globals": "30.2.0", - "@jest/source-map": "30.0.1", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "cjs-module-lexer": "^2.1.0", - "collect-v8-coverage": "^1.0.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "@types/ldapjs": "^2.2.2", + "bcryptjs": "^2.4.0", + "ldapjs": "^2.2.1", + "lru-cache": "^7.10.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.8.0" } }, - "node_modules/jest-snapshot": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", - "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.27.4", - "@babel/generator": "^7.27.5", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "babel-preset-current-node-syntax": "^1.2.0", - "chalk": "^4.1.2", - "expect": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-diff": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "pretty-format": "30.2.0", - "semver": "^7.7.2", - "synckit": "^0.11.8" - }, + "node_modules/ldapauth-fork/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=12" } }, - "node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, + "node_modules/ldapjs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz", + "integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==", + "deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md", "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" + "abstract-logging": "^2.0.0", + "asn1": "^0.2.4", + "assert-plus": "^1.0.0", + "backoff": "^2.5.0", + "ldap-filter": "^0.3.3", + "once": "^1.4.0", + "vasync": "^2.2.0", + "verror": "^1.8.1" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=10.13.0" } }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", "license": "MIT", - "engines": { - "node": ">=8" + "optional": true, + "funding": { + "url": "https://ko-fi.com/killymxi" } }, - "node_modules/jest-validate": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", - "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "camelcase": "^6.3.0", - "chalk": "^4.1.2", - "leven": "^3.1.0", - "pretty-format": "30.2.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=6" } }, - "node_modules/jest-watcher": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", - "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "emittery": "^0.13.1", - "jest-util": "30.2.0", - "string-length": "^4.0.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 0.8.0" } }, - "node_modules/jest-worker": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", - "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", - "dev": true, + "node_modules/libbase64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "license": "MIT", + "optional": true + }, + "node_modules/libmime": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.8.tgz", + "integrity": "sha512-ZrCY+Q66mPvasAfjsQ/IgahzoBvfE1VdtGRpo1hwRB1oK3wJKxhKA3GOcd2a6j7AH5eMFccxK9fBoCpRZTf8ng==", "license": "MIT", + "optional": true, "dependencies": { - "@types/node": "*", - "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.2.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.1.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.2", + "libbase64": "1.3.0", + "libqp": "2.1.1" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "node_modules/libphonenumber-js": { + "version": "1.12.40", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.40.tgz", + "integrity": "sha512-HKGs7GowShNls3Zh+7DTr6wYpPk5jC78l508yQQY3e8ZgJChM3A9JZghmMJZuK+5bogSfuTafpjksGSR3aMIEg==", + "license": "MIT" + }, + "node_modules/libqp": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", + "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "optional": true + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "optional": true, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/joi": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.1.tgz", - "integrity": "sha512-IiQpRyypSnLisQf3PwuN2eIHAsAIGZIrLZkd4zdvIar2bDyhM91ubRjy8a3eYablXsh9BeI/c7dmPYHca5qtoA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/address": "^5.1.1", - "@hapi/formula": "^3.0.2", - "@hapi/hoek": "^11.0.7", - "@hapi/pinpoint": "^2.0.1", - "@hapi/tlds": "^1.1.1", - "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.0.0" - }, - "engines": { - "node": ">= 20" - } + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "devOptional": true, + "license": "MIT" }, - "node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "funding": { - "url": "https://github.com/sponsors/panva" + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "uc.micro": "^2.0.0" } }, - "node_modules/js-beautify": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", - "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "node_modules/liquidjs": { + "version": "10.25.5", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.25.5.tgz", + "integrity": "sha512-GKiKeZjJDdVoQAu+S9rzkYsYnYhcep5W3WwZXgb5f+yq484P/k9JqamBbGYu+LBEixcUAXZr2jogdAIjB3ki1w==", + "license": "MIT", "optional": true, "dependencies": { - "config-chain": "^1.1.13", - "editorconfig": "^1.0.4", - "glob": "^10.4.2", - "js-cookie": "^3.0.5", - "nopt": "^7.2.1" + "commander": "^10.0.0" }, "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" + "liquid": "bin/liquid.js", + "liquidjs": "bin/liquid.js" }, "engines": { - "node": ">=14" + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/liquidjs" } }, - "node_modules/js-beautify/node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "node_modules/liquidjs/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", "optional": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14" } }, - "node_modules/js-beautify/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/load-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz", + "integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + }, + { + "type": "buymeacoffee", + "url": "https://buymeacoffee.com/borewit" + } + ], "license": "MIT", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=13.2.0" } }, - "node_modules/js-beautify/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "optional": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/js-beautify/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "optional": true, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "p-locate": "^5.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=10" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "optional": true, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT", + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/js-beautify/node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "optional": true, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 12.0.0" } }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "optional": true, + "node_modules/logform/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=0.1.90" } }, - "node_modules/js-stringify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", - "optional": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "license": "MIT", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "yallist": "^3.0.2" } }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", "engines": { - "node": ">= 10.16.0" + "node": ">=12" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-bignum": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", - "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", - "engines": { - "node": ">=0.8" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-merge-patch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-1.0.2.tgz", - "integrity": "sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==", + "node_modules/mailparser": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.8.tgz", + "integrity": "sha512-7jSlFGXiianVnhnb6wdutJFloD34488nrHY7r6FNqwXAhZ7YiJDYrKKTxZJ0oSrXcAPHm8YoYnh97xyGtrBQ3w==", "license": "MIT", + "optional": true, "dependencies": { - "fast-deep-equal": "^3.1.3" + "@zone-eu/mailsplit": "5.4.8", + "encoding-japanese": "2.2.0", + "he": "1.2.0", + "html-to-text": "9.0.5", + "iconv-lite": "0.7.2", + "libmime": "5.3.8", + "linkify-it": "5.0.0", + "nodemailer": "8.0.5", + "punycode.js": "2.3.1", + "tlds": "1.261.0" } }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "bin": { - "json5": "lib/cli.js" + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "tmpl": "1.0.5" } }, - "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mathjs": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz", + "integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==", + "license": "Apache-2.0", "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" + "@babel/runtime": "^7.26.10", + "complex.js": "^2.2.5", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "^5.2.1", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.2.1" }, "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" + "mathjs": "bin/cli.js" }, "engines": { - "node": ">=18.0.0" + "node": ">= 18" } }, - "node_modules/jsonschema": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", - "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", - "engines": { - "node": "*" - } + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0", + "optional": true }, - "node_modules/jsonwebtoken": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", - "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", - "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.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jstransformer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", - "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", - "optional": true, - "dependencies": { - "is-promise": "^2.0.0", - "promise": "^7.0.1" + "node": ">= 0.8" } }, - "node_modules/juice": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/juice/-/juice-10.0.1.tgz", - "integrity": "sha512-ZhJT1soxJCkOiO55/mz8yeBKTAJhRzX9WBO+16ZTqNTONnnVlUPyVBIzQ7lDRjaBdTbid+bAnyIon/GM3yp4cA==", - "optional": true, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", "dependencies": { - "cheerio": "1.0.0-rc.12", - "commander": "^6.1.0", - "mensch": "^0.3.4", - "slick": "^1.12.2", - "web-resource-inliner": "^6.0.1" - }, - "bin": { - "juice": "bin/juice" + "fs-monkey": "^1.0.4" }, "engines": { - "node": ">=10.0.0" + "node": ">= 4.0.0" } }, - "node_modules/juice/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "optional": true, + "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/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", + "license": "MIT", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "engines": { + "node": ">= 0.6" } }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "node_modules/kareem": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", - "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", - "license": "Apache-2.0", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "node_modules/migrate-mongo": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/migrate-mongo/-/migrate-mongo-14.0.7.tgz", + "integrity": "sha512-+p7XfJDNaXPTHeo7v/ldYmVLMy8xYda0KMXSqkMUzlVndS39rMGBQHfyLrdmOKMjgciWyWpjekXzRQuj1B7HqA==", + "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "cli-table3": "^0.6.5", + "commander": "^14.0.2" + }, + "bin": { + "migrate-mongo": "bin/migrate-mongo.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "mongodb": "^4.4.1 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/kruptein": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.8.tgz", - "integrity": "sha512-0CyalFA0Cjp3jnziMp0u1uLZW2/ouhQ0mEMfYlroBXNe86na1RwAuwBcdRAegeWZNMfQy/G5fN47g/Axjtqrfw==", + "node_modules/migrate-mongo/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", - "dependencies": { - "asn1.js": "^5.4.1" - }, "engines": { - "node": ">8" + "node": ">=20" } }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT" - }, - "node_modules/ldap-filter": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz", - "integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==", - "dependencies": { - "assert-plus": "^1.0.0" + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "devOptional": true, + "license": "MIT", + "bin": { + "mime": "cli.js" }, "engines": { - "node": ">=0.8" + "node": ">=4.0.0" } }, - "node_modules/ldapauth-fork": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-5.0.5.tgz", - "integrity": "sha512-LWUk76+V4AOZbny/3HIPQtGPWZyA3SW2tRhsWIBi9imP22WJktKLHV1ofd8Jo/wY7Ve6vAT7FCI5mEn3blZTjw==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", "dependencies": { - "@types/ldapjs": "^2.2.2", - "bcryptjs": "^2.4.0", - "ldapjs": "^2.2.1", - "lru-cache": "^7.10.1" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/ldapauth-fork/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" } }, - "node_modules/ldapjs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz", - "integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==", - "deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", "dependencies": { - "abstract-logging": "^2.0.0", - "asn1": "^0.2.4", - "assert-plus": "^1.0.0", - "backoff": "^2.5.0", - "ldap-filter": "^0.3.3", - "once": "^1.4.0", - "vasync": "^2.2.0", - "verror": "^1.8.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10.13.0" + "node": "*" } }, - "node_modules/leac": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", - "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", - "optional": true, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { - "url": "https://ko-fi.com/killymxi" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "node_modules/mjml": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml/-/mjml-5.0.0-beta.2.tgz", + "integrity": "sha512-f8ImzVBa/Kp3IHUw82fDn2kvxHz351F53suF1KGP0imOjU0iKgMoYJGs0BwzHhOhW+XO4zw4btRMsSJc2LOBbQ==", + "license": "MIT", + "optional": true, "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@babel/runtime": "^7.28.4", + "mjml-cli": "5.0.0-beta.2", + "mjml-core": "5.0.0-beta.2", + "mjml-preset-core": "5.0.0-beta.2", + "mjml-validator": "5.0.0-beta.2" }, - "engines": { - "node": ">= 0.8.0" + "bin": { + "mjml": "bin/mjml" } }, - "node_modules/libbase64": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", - "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", - "optional": true + "node_modules/mjml-accordion": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-5.0.0-beta.2.tgz", + "integrity": "sha512-uThyWaQOkZu6143NIt17WINo574kY71NACI53N6wtHaNQJ8h8JxmxM3H/hkFhy2jO2ziYUBZhg9+pcOp8SWGQg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/libmime": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz", - "integrity": "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==", + "node_modules/mjml-body": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-5.0.0-beta.2.tgz", + "integrity": "sha512-jBt1hu1Pnqm74PuwaDN2Fhs2Ub7LSM6YaoUUAVYpd/paex7h09dxGRH3XdQoTnVGbhztshk7LSsRzcfcTen8uQ==", + "license": "MIT", "optional": true, "dependencies": { - "encoding-japanese": "2.2.0", - "iconv-lite": "0.6.3", - "libbase64": "1.3.0", - "libqp": "2.1.1" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/libphonenumber-js": { - "version": "1.12.6", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz", - "integrity": "sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw==" + "node_modules/mjml-button": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-5.0.0-beta.2.tgz", + "integrity": "sha512-T9L4n6pl8s1Lg7xbsvbfVd736E+MJbRglUbMLexE7CemkAzKYN2uttKO1qaFPtxvPUzE+ZCNT1G1WdAZ+9noBw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/libqp": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", - "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", - "optional": true + "node_modules/mjml-carousel": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-5.0.0-beta.2.tgz", + "integrity": "sha512-kSpRIf/1C2Hi3MmN/sibxgpwDjuyxRA5w4CNv5r9t+j6P6ZOJA5HB5s1NEFxzzaAg/ymzaf5viSIQCaLpymOfw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "node_modules/mjml-cli": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-5.0.0-beta.2.tgz", + "integrity": "sha512-G72mqob9JWgOiqUInFjD+G53FzAIzNvJbYobkzFh8MC6u5vn7GB2gUd/knZuvwQzIIbGkfuMDWVjcS/vFNPAlA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "chokidar": "^3.0.0", + "glob": "^10.5.0", + "lodash": "^4.17.21", + "minimatch": "^9.0.3", + "mjml-core": "5.0.0-beta.2", + "mjml-parser-xml": "5.0.0-beta.2", + "mjml-preset-core": "5.0.0-beta.2", + "mjml-validator": "5.0.0-beta.2", + "yargs": "^17.7.2" + }, + "bin": { + "mjml-cli": "bin/mjml" + } }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "node_modules/mjml-cli/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "license": "MIT", "optional": true, "dependencies": { - "uc.micro": "^2.0.0" + "balanced-match": "^1.0.0" } }, - "node_modules/liquidjs": { - "version": "10.21.0", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.21.0.tgz", - "integrity": "sha512-DouqxNU2jfoZzb1LinVjOc/f6ssitGIxiDJT+kEKyYqPSSSd+WmGOAhtWbVm1/n75svu4aQ+FyQ3ctd3wh1bbw==", + "node_modules/mjml-cli/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", "optional": true, "dependencies": { - "commander": "^10.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { - "liquid": "bin/liquid.js", - "liquidjs": "bin/liquid.js" - }, - "engines": { - "node": ">=14" + "glob": "dist/esm/bin.mjs" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/liquidjs" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/liquidjs/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "optional": true, - "engines": { - "node": ">=14" - } + "node_modules/mjml-cli/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC", + "optional": true }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "dev": true, - "license": "MIT", + "node_modules/mjml-cli/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, "engines": { - "node": ">=6.11.5" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, + "node_modules/mjml-cli/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "optional": true, "dependencies": { - "p-locate": "^5.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "license": "MIT" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + "node_modules/mjml-column": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-5.0.0-beta.2.tgz", + "integrity": "sha512-ZlcJJoFL/rxJlhfa6Sm21aWWo4nNUF9R/z7+dBZxDyYsp3tgiKFeiGtGxme9WBdvizkXqmJ+nnXKYHmRwqIP3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "node_modules/mjml-core": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-5.0.0-beta.2.tgz", + "integrity": "sha512-93d2GWeWdLEbHGXBa6haVleV/ZAj5EI0lEzY8KOGGFvJQoSrvTUna5fhiNop0CkCpohAWEJsR7PjTAS3URqxGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "cheerio": "1.0.0", + "cssnano": "^7.1.2", + "cssnano-preset-lite": "^4.0.4", + "detect-node": "^2.0.4", + "htmlnano": "^3.2.0", + "juice": "^11.0.0", + "lodash": "^4.17.21", + "mjml-parser-xml": "5.0.0-beta.2", + "mjml-validator": "5.0.0-beta.2", + "postcss": "^8.5.8", + "prettier": "^3.8.1" + } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "node_modules/mjml-divider": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-5.0.0-beta.2.tgz", + "integrity": "sha512-zGgN7uAqYmzQK6fqjtGLEctQ6OqV6JlvbsqL892FsO7v6r6DZapDBnNdUYz1b6j0tkZqfNMzIptGCfD/Om58Mg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "node_modules/mjml-group": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-5.0.0-beta.2.tgz", + "integrity": "sha512-TZ/S8SkPBGA+7Rq5FSjNZHnPTu3pIJElUiu+acW5Y7tmSeYkPocCyG+3Nxr+2GNBeVHvhlcq+nXTFJpujlfkoQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "node_modules/mjml-head": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-5.0.0-beta.2.tgz", + "integrity": "sha512-xLy2+uFTdGgMlmSZFB05ng/H1xeUp1MiPgDlEYiowcp4r27zVuGDT2VUZIQkH5cv7UasEMXfMTJZ23qAvERjjg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, + "node_modules/mjml-head-attributes": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-5.0.0-beta.2.tgz", + "integrity": "sha512-BO07AJuxcFJu6YJcyNIDOEuWv1KIFVSv4taEujy0T9iVMuudTHdpsUdkgPIfZx3G7Amn+zvcJCY6xLtFpis5LQ==", + "license": "MIT", + "optional": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/logform": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", - "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "node_modules/mjml-head-breakpoint": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-5.0.0-beta.2.tgz", + "integrity": "sha512-bBcnqVz9RlkhUMWpdsJmmQGc61mxhZrwD6RublSZJMOX9W3x/XrfGzcJDs0RN9oLQjySBrSOYySnDozaPCxbyQ==", "license": "MIT", + "optional": true, "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/logform/node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "node_modules/mjml-head-font": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-5.0.0-beta.2.tgz", + "integrity": "sha512-J18AEbHMD7XMhYSEhZlJwmjpOoLFoQSb4ywLX5k5Gp75KH3H4NsqV/UVFZiCPdi6rksWaa0T2Vhn2cdHnHuyrg==", "license": "MIT", - "engines": { - "node": ">=0.1.90" + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", - "optional": true + "node_modules/mjml-head-html-attributes": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-5.0.0-beta.2.tgz", + "integrity": "sha512-CVYgy3J/d5GQt7b7K1GZMl0hoeKalvByvZLkH2IJdjxThBUC+14JEoyjaW7auiFEScUnx3CpymPs9ozExH/PnA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" + } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", + "node_modules/mjml-head-preview": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-5.0.0-beta.2.tgz", + "integrity": "sha512-33I+Pujw+HSCPBNYtTCSzbBN2WxoIP1AMfXYN7infBFqUAdXf2btAHddB77JfopQS5U3/7Ufxjd3GzYtKBa86g==", + "license": "MIT", + "optional": true, "dependencies": { - "yallist": "^3.0.2" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/luxon": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", - "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "node_modules/mjml-head-style": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-5.0.0-beta.2.tgz", + "integrity": "sha512-rySJtKbUpt6MXnZ2dQFRFnEPSfWu9MtlAKpdgqOS91LgE/j1L6rUh7iYW3DI3eS9lyV45etDOIvNhdIM+KaYfw==", "license": "MIT", - "engines": { - "node": ">=12" + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, + "node_modules/mjml-head-title": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-5.0.0-beta.2.tgz", + "integrity": "sha512-o0TU17mRHCRChSu6uiKfPUPrgNpzA3pUv3vGEDn4zINSx+W6UJbuKRotgkptuWrfDrHwqx2yNsFs3t7WZ86GkA==", + "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/mailparser": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz", - "integrity": "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==", + "node_modules/mjml-hero": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-5.0.0-beta.2.tgz", + "integrity": "sha512-kH2z02VtOacH/c8IT+EsHJMf4Ce9ZXp0ErR0FgwpaeSpG+XHw2Ov8s61abXOh7QFdPUkhgVUydqz2+nQBp0nwg==", + "license": "MIT", "optional": true, "dependencies": { - "encoding-japanese": "2.2.0", - "he": "1.2.0", - "html-to-text": "9.0.5", - "iconv-lite": "0.6.3", - "libmime": "5.3.6", - "linkify-it": "5.0.0", - "mailsplit": "5.4.2", - "nodemailer": "6.9.16", - "punycode.js": "2.3.1", - "tlds": "1.255.0" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/mailparser/node_modules/nodemailer": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", - "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "node_modules/mjml-image": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-5.0.0-beta.2.tgz", + "integrity": "sha512-eLF6vv5lvdxU1y3ahAx3QJIhW1G57Ou7Ur9UGZ5W5bnjIbS77GjHqMMO95hVPAdw54j8YGuwGUAj7cI+ZrRozg==", + "license": "MIT", "optional": true, - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/mailsplit": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz", - "integrity": "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==", + "node_modules/mjml-navbar": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-5.0.0-beta.2.tgz", + "integrity": "sha512-+3UaYTYGpQMKCVyqt/mp+WDs7lE2n0mmbIYrADxmfnRPrixu4zz72TSMvdHKL0hSRP/IIC2tUOh6+pxihV0mJQ==", + "license": "MIT", "optional": true, "dependencies": { - "libbase64": "1.3.0", - "libmime": "5.3.6", - "libqp": "2.1.1" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "node_modules/mjml-parser-xml": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-5.0.0-beta.2.tgz", + "integrity": "sha512-CVWdHy75ftf0GGvDT4juX5AQMvzH/bx3zlNos37hB0v7onJ1bjHfFzDYedzzll00aGhOM1HiMGmX0mrObhYKqQ==", "license": "MIT", + "optional": true, "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/runtime": "^7.28.4", + "detect-node": "2.1.0", + "htmlparser2": "^9.1.0", + "lodash": "^4.17.21" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "node_modules/mjml-preset-core": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-5.0.0-beta.2.tgz", + "integrity": "sha512-yZyH8t7BcTKgLXyelU71Ye2IvuQGlhqv8hOEUIiw66ZMcnWWnWJlcaVEkaFPSnIX/IwLNyXIM4LQ1ZHSX3rgxg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "mjml-accordion": "5.0.0-beta.2", + "mjml-body": "5.0.0-beta.2", + "mjml-button": "5.0.0-beta.2", + "mjml-carousel": "5.0.0-beta.2", + "mjml-column": "5.0.0-beta.2", + "mjml-divider": "5.0.0-beta.2", + "mjml-group": "5.0.0-beta.2", + "mjml-head": "5.0.0-beta.2", + "mjml-head-attributes": "5.0.0-beta.2", + "mjml-head-breakpoint": "5.0.0-beta.2", + "mjml-head-font": "5.0.0-beta.2", + "mjml-head-html-attributes": "5.0.0-beta.2", + "mjml-head-preview": "5.0.0-beta.2", + "mjml-head-style": "5.0.0-beta.2", + "mjml-head-title": "5.0.0-beta.2", + "mjml-hero": "5.0.0-beta.2", + "mjml-image": "5.0.0-beta.2", + "mjml-navbar": "5.0.0-beta.2", + "mjml-raw": "5.0.0-beta.2", + "mjml-section": "5.0.0-beta.2", + "mjml-social": "5.0.0-beta.2", + "mjml-spacer": "5.0.0-beta.2", + "mjml-table": "5.0.0-beta.2", + "mjml-text": "5.0.0-beta.2", + "mjml-wrapper": "5.0.0-beta.2" + } }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, + "node_modules/mjml-raw": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-5.0.0-beta.2.tgz", + "integrity": "sha512-H4gN+wJRKS7BKlX8vdXCzyrLiCi6qeTDDDB3nm6CwSg5bxlE+19bVHHUXHxBjkeV5acipXDhbaCIHLUfeRFN0g==", + "license": "MIT", + "optional": true, "dependencies": { - "tmpl": "1.0.5" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" + "node_modules/mjml-section": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-5.0.0-beta.2.tgz", + "integrity": "sha512-Z7x56JTcn2yKvqlcL7gRQrcyLimQC4BZJKk3JQN8xIByZucRfVfmE5L+2KA78+uc7NMnNKIPl7eXYECun6fM8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/mathjs": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.1.0.tgz", - "integrity": "sha512-HfnAcScQm9drGryodlDqeS3WAl4gUTYGDcOtcqL/8s23MZ28Ib1i8XnYK3ZdjNuaW/L4BAp9lIp8vxAMrcuu1w==", - "license": "Apache-2.0", + "node_modules/mjml-social": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-5.0.0-beta.2.tgz", + "integrity": "sha512-006HWAszTUP7vNJvQnPrX1CvOvWAy9AEfhAVlkNKyEkr/F+z1Qpq+dVE7W1jXsq7GUeWT6AIr6EQrmKRXe+19A==", + "license": "MIT", + "optional": true, "dependencies": { - "@babel/runtime": "^7.26.10", - "complex.js": "^2.2.5", - "decimal.js": "^10.4.3", - "escape-latex": "^1.2.0", - "fraction.js": "^5.2.1", - "javascript-natural-sort": "^0.7.1", - "seedrandom": "^3.0.5", - "tiny-emitter": "^2.1.0", - "typed-function": "^4.2.1" - }, - "bin": { - "mathjs": "bin/cli.js" - }, - "engines": { - "node": ">= 18" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "engines": { - "node": ">= 0.8" + "node_modules/mjml-spacer": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-5.0.0-beta.2.tgz", + "integrity": "sha512-mKpxKWPHYlgd65hFLNddzgjqykqB/4crfrkAdWP06nCsLZpxRe94jLVyKHHwfCv8XUGsg+Srh+79kfQYSF7kig==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, + "node_modules/mjml-table": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-5.0.0-beta.2.tgz", + "integrity": "sha512-o+EiFn4q+Pjbbi3jQLpLs65Ss3TGW/0Z/7GGBL35L4sLDJ/+4ek0pgkTjmWlS6SgXSy2Oua9MCZj2qX3MjfzWQ==", + "license": "MIT", + "optional": true, "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "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/mensch": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", - "optional": true - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/mjml-text": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-5.0.0-beta.2.tgz", + "integrity": "sha512-gLoZTMucbK/ffuUFJiKBpm7Pi+m9zyjqL/RKePUExzH8Ad5qDCqjND2QFKuuSLy8jp02qjnKVudbtWnF2H3ALQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" + "node_modules/mjml-validator": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-5.0.0-beta.2.tgz", + "integrity": "sha512-zVztkHNlkxkOre+7p5BRL71Y+1EKUs1awpyw2T+Cs7UAimWiaFiB9FhGEdnTffTc/HWfrmSKp3wq4W1zbuSRsg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.28.4" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, + "node_modules/mjml-wrapper": { + "version": "5.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-5.0.0-beta.2.tgz", + "integrity": "sha512-dXgxXZpyRkrSdL6z8xqzMiF3WacJ+DYlqEgtAVmRd4lUAB/UlgNLrpzQDpmFKxc0is8JB2lB6hF7APO1nT7BBQ==", + "license": "MIT", + "optional": true, "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" + "@babel/runtime": "^7.28.4", + "lodash": "^4.17.21", + "mjml-core": "5.0.0-beta.2", + "mjml-section": "5.0.0-beta.2" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, "engines": { - "node": ">=8.6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/migrate-mongo": { - "version": "14.0.7", - "resolved": "https://registry.npmjs.org/migrate-mongo/-/migrate-mongo-14.0.7.tgz", - "integrity": "sha512-+p7XfJDNaXPTHeo7v/ldYmVLMy8xYda0KMXSqkMUzlVndS39rMGBQHfyLrdmOKMjgciWyWpjekXzRQuj1B7HqA==", + "node_modules/mocha": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, "license": "MIT", "dependencies": { - "cli-table3": "^0.6.5", - "commander": "^14.0.2" + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" }, "bin": { - "migrate-mongo": "bin/migrate-mongo.js" + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" }, "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "mongodb": "^4.4.1 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/migrate-mongo/node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=20" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "devOptional": true, - "bin": { - "mime": "cli.js" + "node_modules/mocha/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "engines": { - "node": ">= 0.6" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "node_modules/mocha/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", "dependencies": { - "mime-db": "^1.54.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">= 0.6" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/mocha/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC" }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, + "node_modules/mocha/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.2" }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mjml": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.15.3.tgz", - "integrity": "sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "mjml-cli": "4.15.3", - "mjml-core": "4.15.3", - "mjml-migrate": "4.15.3", - "mjml-preset-core": "4.15.3", - "mjml-validator": "4.15.3" }, - "bin": { - "mjml": "bin/mjml" - } - }, - "node_modules/mjml-accordion": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.15.3.tgz", - "integrity": "sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mjml-body": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.15.3.tgz", - "integrity": "sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==", - "optional": true, + "node_modules/mocha/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mjml-button": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.15.3.tgz", - "integrity": "sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/mocha/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/mjml-carousel": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.15.3.tgz", - "integrity": "sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==", - "optional": true, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mjml-cli": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.15.3.tgz", - "integrity": "sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==", - "optional": true, + "node_modules/mongodb": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", + "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.23.9", - "chokidar": "^3.0.0", - "glob": "^10.3.10", - "html-minifier": "^4.0.0", - "js-beautify": "^1.6.14", - "lodash": "^4.17.21", - "minimatch": "^9.0.3", - "mjml-core": "4.15.3", - "mjml-migrate": "4.15.3", - "mjml-parser-xml": "4.15.3", - "mjml-validator": "4.15.3", - "yargs": "^17.7.2" + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.2" }, - "bin": { - "mjml-cli": "bin/mjml" + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "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/mjml-cli/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "optional": true, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0" + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" } }, - "node_modules/mjml-cli/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "optional": true, + "node_modules/mongoose": { + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.23.0.tgz", + "integrity": "sha512-Bul4Ha6J8IqzFrb0B1xpVzkC3S0sk43dmLSnhFOn8eJlZiLwL5WO6cRymmjaADdCMjUcCpj2ce8hZI6O4ZFSug==", + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "bson": "^6.10.4", + "kareem": "2.6.3", + "mongodb": "~6.20.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" }, "engines": { - "node": ">= 8.10.0" + "node": ">=16.20.1" }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "type": "opencollective", + "url": "https://opencollective.com/mongoose" } }, - "node_modules/mjml-cli/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "optional": true, + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "debug": "4.x" }, "engines": { - "node": ">= 6" + "node": ">=14.0.0" } }, - "node_modules/mjml-cli/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "optional": true, + "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/multer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "type-is": "^1.6.18" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 10.16.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/mjml-cli/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "optional": true, + "node_modules/multer/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==", + "license": "MIT", "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">= 0.6" } }, - "node_modules/mjml-cli/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "optional": true, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "mime-db": "1.52.0" }, "engines": { - "node": ">=8.10.0" + "node": ">= 0.6" } }, - "node_modules/mjml-column": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.15.3.tgz", - "integrity": "sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==", - "optional": true, + "node_modules/multer/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==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/mjml-core": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.15.3.tgz", - "integrity": "sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "cheerio": "1.0.0-rc.12", - "detect-node": "^2.0.4", - "html-minifier": "^4.0.0", - "js-beautify": "^1.6.14", - "juice": "^10.0.0", - "lodash": "^4.17.21", - "mjml-migrate": "4.15.3", - "mjml-parser-xml": "4.15.3", - "mjml-validator": "4.15.3" + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/mjml-divider": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.15.3.tgz", - "integrity": "sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/mjml-group": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.15.3.tgz", - "integrity": "sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" } }, - "node_modules/mjml-head": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.15.3.tgz", - "integrity": "sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "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" } }, - "node_modules/mjml-head-attributes": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.15.3.tgz", - "integrity": "sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" - } + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, - "node_modules/mjml-head-breakpoint": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.15.3.tgz", - "integrity": "sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" - } + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, + "license": "MIT" }, - "node_modules/mjml-head-font": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.15.3.tgz", - "integrity": "sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/node-addon-api": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz", + "integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" } }, - "node_modules/mjml-head-html-attributes": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.15.3.tgz", - "integrity": "sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" } }, - "node_modules/mjml-head-preview": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.15.3.tgz", - "integrity": "sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==", - "optional": true, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "lodash": "^4.17.21" } }, - "node_modules/mjml-head-style": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.15.3.tgz", - "integrity": "sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==", - "optional": true, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/mjml-head-title": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.15.3.tgz", - "integrity": "sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/mjml-hero": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.15.3.tgz", - "integrity": "sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/nodemailer": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.5.tgz", + "integrity": "sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/mjml-image": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.15.3.tgz", - "integrity": "sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mjml-migrate": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.15.3.tgz", - "integrity": "sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==", - "optional": true, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "js-beautify": "^1.6.14", - "lodash": "^4.17.21", - "mjml-core": "4.15.3", - "mjml-parser-xml": "4.15.3", - "yargs": "^17.7.2" + "path-key": "^3.0.0" }, - "bin": { - "migrate": "lib/cli.js" + "engines": { + "node": ">=8" } }, - "node_modules/mjml-navbar": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.15.3.tgz", - "integrity": "sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/mjml-parser-xml": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.15.3.tgz", - "integrity": "sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==", + "node_modules/nunjucks": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", + "license": "BSD-2-Clause", "optional": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "detect-node": "2.1.0", - "htmlparser2": "^9.1.0", - "lodash": "^4.17.15" - } - }, - "node_modules/mjml-parser-xml/node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" + "a-sync-waterfall": "^1.0.0", + "asap": "^2.0.3", + "commander": "^5.1.0" + }, + "bin": { + "nunjucks-precompile": "bin/precompile" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "chokidar": "^3.3.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true } - ], - "optional": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" } }, - "node_modules/mjml-preset-core": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.15.3.tgz", - "integrity": "sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==", + "node_modules/nunjucks/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "mjml-accordion": "4.15.3", - "mjml-body": "4.15.3", - "mjml-button": "4.15.3", - "mjml-carousel": "4.15.3", - "mjml-column": "4.15.3", - "mjml-divider": "4.15.3", - "mjml-group": "4.15.3", - "mjml-head": "4.15.3", - "mjml-head-attributes": "4.15.3", - "mjml-head-breakpoint": "4.15.3", - "mjml-head-font": "4.15.3", - "mjml-head-html-attributes": "4.15.3", - "mjml-head-preview": "4.15.3", - "mjml-head-style": "4.15.3", - "mjml-head-title": "4.15.3", - "mjml-hero": "4.15.3", - "mjml-image": "4.15.3", - "mjml-navbar": "4.15.3", - "mjml-raw": "4.15.3", - "mjml-section": "4.15.3", - "mjml-social": "4.15.3", - "mjml-spacer": "4.15.3", - "mjml-table": "4.15.3", - "mjml-text": "4.15.3", - "mjml-wrapper": "4.15.3" + "engines": { + "node": ">= 6" } }, - "node_modules/mjml-raw": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.15.3.tgz", - "integrity": "sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mjml-section": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.15.3.tgz", - "integrity": "sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "node_modules/mjml-social": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.15.3.tgz", - "integrity": "sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mjml-spacer": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.15.3.tgz", - "integrity": "sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/oidc-token-hash": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz", + "integrity": "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || >=12.0.0" } }, - "node_modules/mjml-table": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.15.3.tgz", - "integrity": "sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==", - "optional": true, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/mjml-text": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.15.3.tgz", - "integrity": "sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==", - "optional": true, - "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3" + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "node_modules/mjml-validator": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.15.3.tgz", - "integrity": "sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==", - "optional": true, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.23.9" + "wrappy": "1" } }, - "node_modules/mjml-wrapper": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.15.3.tgz", - "integrity": "sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==", - "optional": true, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "lodash": "^4.17.21", - "mjml-core": "4.15.3", - "mjml-section": "4.15.3" + "fn.name": "1.x.x" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "devOptional": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "mimic-fn": "^2.1.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha": { - "version": "11.7.5", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", - "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", - "dev": true, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", + "optional": true, "dependencies": { - "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", - "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", - "ms": "^2.1.3", - "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, + "node_modules/openid-client": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", + "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "jose": "^4.15.9", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/panva" } }, - "node_modules/mocha/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "yallist": "^4.0.0" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "engines": { + "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/openid-client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.8.0" } }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mongodb": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", - "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==", - "license": "Apache-2.0", + "node_modules/p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^6.10.4", - "mongodb-connection-string-url": "^3.0.2" + "p-timeout": "^3.1.0" }, "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.3.2", - "socks": "^2.7.1" + "node": ">=8" }, - "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 - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mongodb-connection-string-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", - "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^14.1.0 || ^13.0.0" + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" } }, - "node_modules/mongoose": { - "version": "8.20.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.20.3.tgz", - "integrity": "sha512-AQk63Ry4YM/lWJRt/D5P7UiRjKT+z+vD0NkNKgeQ35TioBC7kuI6wBzhu6/kyrNXg+WotFidW1icEWLNC1rUfg==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { - "bson": "^6.10.4", - "kareem": "2.6.3", - "mongodb": "~6.20.0", - "mpath": "0.9.0", - "mquery": "5.0.0", - "ms": "2.1.3", - "sift": "17.1.3" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=16.20.1" + "node": ">=10" }, "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==", - "engines": { - "node": ">=4.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mquery": { + "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", - "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "4.x" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==" - }, - "node_modules/multer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", - "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", "license": "MIT", + "optional": true, "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" + "p-finally": "^1.0.0" }, "engines": { - "node": ">= 10.16.0" + "node": ">=8" } }, - "node_modules/multer/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==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/multer/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==", + "node_modules/p-wait-for": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", + "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", "license": "MIT", + "optional": true, + "dependencies": { + "p-timeout": "^3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/multer/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==", + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "devOptional": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/multer/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==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "devOptional": true, "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">= 0.6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "optional": true, + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/napi-postinstall": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", - "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==", - "dev": true, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", "license": "MIT", - "bin": { - "napi-postinstall": "lib/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "optional": true, + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" }, "funding": { - "url": "https://opencollective.com/napi-postinstall" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "optional": true, + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "optional": true, "engines": { - "node": ">= 0.6" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "optional": true - }, - "node_modules/no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "license": "MIT", "optional": true, "dependencies": { - "lower-case": "^1.1.1" + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" } }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node_modules/node-addon-api": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz", - "integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { - "node": "^18 || ^20 || >= 21" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21" + "node": ">= 0.8" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 0.4.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" } }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" + "node_modules/passport-ldapauth": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-3.0.1.tgz", + "integrity": "sha512-TRRx3BHi8GC8MfCT9wmghjde/EGeKjll7zqHRRfGRxXbLcaDce2OftbQrFG7/AWaeFhR6zpZHtBQ/IkINdLVjQ==", + "license": "MIT", + "dependencies": { + "ldapauth-fork": "^5.0.1", + "passport-strategy": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } }, - "node_modules/nodemailer": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", - "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", + "node_modules/passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "dependencies": { + "passport-strategy": "1.x.x" + }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.4.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, "engines": { "node": ">=8" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "optional": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT", + "optional": true + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, "engines": { - "node": ">= 0.4" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/oidc-token-hash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.0.tgz", - "integrity": "sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "license": "BlueOak-1.0.0", "engines": { - "node": "^10.13.0 || >=12.0.0" + "node": "20 || >=22" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", "license": "MIT", - "dependencies": { - "fn.name": "1.x.x" + "optional": true, + "funding": { + "url": "https://ko-fi.com/killymxi" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "optional": true, - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/openid-client": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", - "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", "dependencies": { - "jose": "^4.15.9", - "lru-cache": "^6.0.0", - "object-hash": "^2.2.0", - "oidc-token-hash": "^5.0.3" + "find-up": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/panva" + "engines": { + "node": ">=8" } }, - "node_modules/openid-client/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/openid-client/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "p-limit": "^2.2.0" }, "engines": { "node": ">=8" } }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "optional": true, "dependencies": { - "p-timeout": "^3.1.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10 || ^12 || >=14" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "node_modules/postcss-calc": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", + "license": "MIT", "optional": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=4" + "node": "^18.12 || ^20.9 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.38" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "node_modules/postcss-colormin": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.6.tgz", + "integrity": "sha512-oXM2mdx6IBTRm39797QguYzVEWzbdlFiMNfq88fCCN1Wepw3CYmJ/1/Ifa/KjWo+j5ZURDl2NTldLJIw51IeNQ==", + "license": "MIT", + "optional": true, "dependencies": { - "yocto-queue": "^0.1.0" + "browserslist": "^4.28.1", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "node_modules/postcss-convert-values": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.9.tgz", + "integrity": "sha512-l6uATQATZaCa0bckHV+r6dLXfWtUBKXxO3jK+AtxxJJtgMPD+VhhPCCx51I4/5w8U5uHV67g3w7PXj+V3wlMlg==", + "license": "MIT", + "optional": true, "dependencies": { - "p-limit": "^3.0.2" + "browserslist": "^4.28.1", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "node_modules/postcss-discard-comments": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.6.tgz", + "integrity": "sha512-Sq+Fzj1Eg5/CPf1ERb0wS1Im5cvE2gDXCE+si4HCn1sf+jpQZxDI4DXEp8t77B/ImzDceWE2ebJQFXdqZ6GRJw==", + "license": "MIT", "optional": true, "dependencies": { - "p-finally": "^1.0.0" + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, + "node_modules/postcss-discard-duplicates": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", "license": "MIT", + "optional": true, "engines": { - "node": ">=6" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/p-wait-for": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", - "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "node_modules/postcss-discard-empty": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", + "license": "MIT", "optional": true, - "dependencies": { - "p-timeout": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + "node_modules/postcss-discard-overridden": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", + "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } }, - "node_modules/param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "node_modules/postcss-merge-longhand": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", + "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", + "license": "MIT", "optional": true, "dependencies": { - "no-case": "^2.2.0" + "postcss-value-parser": "^4.2.0", + "stylehacks": "^7.0.5" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "node_modules/postcss-merge-rules": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.8.tgz", + "integrity": "sha512-BOR1iAM8jnr7zoQSlpeBmCsWV5Uudi/+5j7k05D0O/WP3+OFMPD86c1j/20xiuRtyt45bhxw/7hnhZNhW2mNFA==", + "license": "MIT", + "optional": true, "dependencies": { - "callsites": "^3.0.0" + "browserslist": "^4.28.1", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^5.0.1", + "postcss-selector-parser": "^7.1.1" }, "engines": { - "node": ">=6" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "node_modules/postcss-minify-font-values": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", + "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parse5": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "node_modules/postcss-minify-gradients": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", + "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", + "license": "MIT", "optional": true, "dependencies": { - "entities": "^4.5.0" + "colord": "^2.9.3", + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "node_modules/postcss-minify-params": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.6.tgz", + "integrity": "sha512-YOn02gC68JijlaXVuKvFSCvQOhTpblkcfDre2hb/Aaa58r2BIaK4AtE/cyZf2wV7YKAG+UlP9DT+By0ry1E4VQ==", + "license": "MIT", "optional": true, "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" + "browserslist": "^4.28.1", + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parseley": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", - "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "node_modules/postcss-minify-selectors": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.6.tgz", + "integrity": "sha512-lIbC0jy3AAwDxEgciZlBullDiMBeBCT+fz5G8RcA9MWqh/hfUkpOI3vNDUNEZHgokaoiv0juB9Y8fGcON7rU/A==", + "license": "MIT", "optional": true, "dependencies": { - "leac": "^0.6.0", - "peberminta": "^0.9.0" + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.1" }, - "funding": { - "url": "https://ko-fi.com/killymxi" + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/postcss-normalize-charset": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", + "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", + "license": "MIT", + "optional": true, "engines": { - "node": ">= 0.8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/passport": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", - "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "node_modules/postcss-normalize-display-values": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", + "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", + "license": "MIT", + "optional": true, "dependencies": { - "passport-strategy": "1.x.x", - "pause": "0.0.1", - "utils-merge": "^1.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">= 0.4.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jaredhanson" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/passport-jwt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", - "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "node_modules/postcss-normalize-positions": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", + "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", + "license": "MIT", + "optional": true, "dependencies": { - "jsonwebtoken": "^9.0.0", - "passport-strategy": "^1.0.0" + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/passport-ldapauth": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-3.0.1.tgz", - "integrity": "sha512-TRRx3BHi8GC8MfCT9wmghjde/EGeKjll7zqHRRfGRxXbLcaDce2OftbQrFG7/AWaeFhR6zpZHtBQ/IkINdLVjQ==", + "node_modules/postcss-normalize-repeat-style": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", + "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", + "license": "MIT", + "optional": true, "dependencies": { - "ldapauth-fork": "^5.0.1", - "passport-strategy": "^1.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=0.8.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/passport-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", - "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "node_modules/postcss-normalize-string": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", + "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", + "license": "MIT", + "optional": true, "dependencies": { - "passport-strategy": "1.x.x" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">= 0.4.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "node_modules/postcss-normalize-timing-functions": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", + "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", + "license": "MIT", + "optional": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">= 0.4.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/postcss-normalize-unicode": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.6.tgz", + "integrity": "sha512-z6bwTV84YW6ZvvNoaNLuzRW4/uWxDKYI1iIDrzk6D2YTL7hICApy+Q1LP6vBEsljX8FM7YSuV9qI79XESd4ddQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "browserslist": "^4.28.1", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, + "node_modules/postcss-normalize-url": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", + "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", "license": "MIT", + "optional": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/postcss-normalize-whitespace": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "optional": true - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/postcss-ordered-values": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", + "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", + "license": "MIT", + "optional": true, "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "node_modules/postcss-reduce-initial": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.6.tgz", + "integrity": "sha512-G6ZyK68AmrPdMB6wyeA37ejnnRG2S8xinJrZJnOv+IaRKf6koPAVbQsiC7MfkmXaGmF1UO+QCijb27wfpxuRNg==", + "license": "MIT", + "optional": true, + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-api": "^3.0.0" + }, "engines": { - "node": ">=16" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "node_modules/postcss-reduce-transforms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", + "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", + "license": "MIT", + "optional": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" - }, - "node_modules/peberminta": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", - "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", "optional": true, - "funding": { - "url": "https://ko-fi.com/killymxi" + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, + "node_modules/postcss-svgo": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.1.tgz", + "integrity": "sha512-zU9H9oEDrUFKa0JB7w+IYL7Qs9ey1mZyjhbf0KLxwJDdDRtoPvCmaEfknzqfHj44QS9VD6c5sJnBAVYTLRg/Sg==", + "license": "MIT", + "optional": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^4.0.1" + }, "engines": { - "node": ">=12" + "node": "^18.12.0 || ^20.9.0 || >= 18" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, + "node_modules/postcss-unique-selectors": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.5.tgz", + "integrity": "sha512-3QoYmEt4qg/rUWDn6Tc8+ZVPmbp4G1hXDtCNWDx0st8SjtCbRcxRXDDM1QrEiXGG3A45zscSJFb4QH90LViyxg==", + "license": "MIT", + "optional": true, + "dependencies": { + "postcss-selector-parser": "^7.1.1" + }, "engines": { - "node": ">= 6" + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/pkg-dir": { + "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT", + "optional": true + }, + "node_modules/posthtml": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.7.tgz", + "integrity": "sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw==", "license": "MIT", + "optional": true, "dependencies": { - "find-up": "^4.0.0" + "posthtml-parser": "^0.11.0", + "posthtml-render": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=12.0.0" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, + "node_modules/posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", "license": "MIT", + "optional": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "htmlparser2": "^7.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, + "node_modules/posthtml-parser/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "license": "MIT", + "optional": true, "dependencies": { - "p-locate": "^4.1.0" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/posthtml-parser/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "optional": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/posthtml-parser/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "domelementtype": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", + "node_modules/posthtml-parser/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "optional": true, "dependencies": { - "p-try": "^2.0.0" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/posthtml-parser/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "license": "BSD-2-Clause", + "optional": true, "engines": { - "node": ">=6" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/posthtml-parser/node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, + "node_modules/posthtml-render": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", + "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", "license": "MIT", + "optional": true, "dependencies": { - "p-limit": "^2.2.0" + "is-json": "^2.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/precond": { @@ -13251,6 +13539,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -13259,7 +13548,7 @@ "version": "3.8.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -13285,9 +13574,9 @@ } }, "node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13313,17 +13602,18 @@ } }, "node_modules/preview-email": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.1.0.tgz", - "integrity": "sha512-ZtV1YrwscEjlrUzYrTSs6Nwo49JM3pXLM4fFOBSC3wSni+bxaWlw9/Qgk75PZO8M7cX2EybmL2iwvaV3vkAttw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.1.3.tgz", + "integrity": "sha512-M/R82S5iYDpNJIPcrtc3OToNbUATXmuV3b3bEcyOnTFzThjkChJqpoOwlm7AXvpEKZ9OFaglOsl/RxU5cnMC6g==", + "license": "MIT", "optional": true, "dependencies": { "ci-info": "^3.8.0", - "display-notification": "2.0.0", + "display-notification": "^3.0.0", "fixpack": "^4.0.0", "get-port": "5.1.1", - "mailparser": "^3.7.1", - "nodemailer": "^6.9.13", + "mailparser": "^3.9.6", + "nodemailer": "^8.0.4", "open": "7", "p-event": "4.2.0", "p-wait-for": "3.2.0", @@ -13334,6 +13624,22 @@ "node": ">=14" } }, + "node_modules/preview-email/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/preview-email/node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -13342,6 +13648,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "optional": true, "bin": { "uuid": "dist/bin/uuid" @@ -13351,21 +13658,17 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "license": "MIT", "optional": true, "dependencies": { "asap": "~2.0.3" } }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "optional": true - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -13375,17 +13678,22 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pug": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", - "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "license": "MIT", "optional": true, "dependencies": { - "pug-code-gen": "^3.0.3", + "pug-code-gen": "^3.0.4", "pug-filters": "^4.0.0", "pug-lexer": "^5.0.1", "pug-linker": "^4.0.0", @@ -13399,6 +13707,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "license": "MIT", "optional": true, "dependencies": { "constantinople": "^4.0.1", @@ -13407,9 +13716,10 @@ } }, "node_modules/pug-code-gen": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", - "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "license": "MIT", "optional": true, "dependencies": { "constantinople": "^4.0.1", @@ -13426,12 +13736,14 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "license": "MIT", "optional": true }, "node_modules/pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "license": "MIT", "optional": true, "dependencies": { "constantinople": "^4.0.1", @@ -13445,6 +13757,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "license": "MIT", "optional": true, "dependencies": { "character-parser": "^2.2.0", @@ -13456,6 +13769,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^2.0.0", @@ -13466,6 +13780,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "license": "MIT", "optional": true, "dependencies": { "object-assign": "^4.1.1", @@ -13476,6 +13791,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^2.0.0", @@ -13486,12 +13802,14 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "license": "MIT", "optional": true }, "node_modules/pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^2.0.0" @@ -13501,12 +13819,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "license": "MIT", "optional": true }, "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" } @@ -13515,6 +13835,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -13538,9 +13859,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -13555,12 +13876,14 @@ "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -13570,6 +13893,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -13578,6 +13902,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13597,26 +13922,11 @@ "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, "dependencies": { "deep-extend": "^0.6.0", @@ -13632,6 +13942,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -13659,42 +13970,43 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">= 14.18.0" + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "optional": true, - "engines": { - "node": ">= 0.10" - } + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13703,6 +14015,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13710,15 +14023,17 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", "optional": true, "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -13759,7 +14074,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -13769,6 +14085,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -13781,15 +14098,16 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/rimraf": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.2.tgz", - "integrity": "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "license": "BlueOak-1.0.0", "dependencies": { - "glob": "^13.0.0", + "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, "bin": { @@ -13802,67 +14120,11 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "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", @@ -13877,145 +14139,30 @@ "node_modules/router/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==" + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" }, "node_modules/run-applescript": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-3.2.0.tgz", - "integrity": "sha512-Ep0RsvAjnRcBX1p5vogbaBdAGu/8j/ewpvGqnQYunnLd9SM0vWcPJewPKNnWFggf0hF0pwIgwV5XK7qQ7UZ8Qg==", - "optional": true, - "dependencies": { - "execa": "^0.10.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-applescript/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "optional": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/run-applescript/node_modules/execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "optional": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-applescript/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-applescript/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-applescript/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "optional": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-applescript/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-applescript/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/run-applescript/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "license": "MIT", "optional": true, "dependencies": { - "shebang-regex": "^1.0.0" + "execa": "^5.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-applescript/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-applescript/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "optional": true - }, - "node_modules/run-applescript/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "optional": true, - "dependencies": { - "isexe": "^2.0.0" + "node": ">=12" }, - "bin": { - "which": "bin/which" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -14037,7 +14184,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-stable-stringify": { "version": "2.5.0", @@ -14051,13 +14199,25 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=11.0.0" + } }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -14072,10 +14232,11 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14092,6 +14253,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -14100,33 +14262,26 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/secure-json-parse": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-3.0.2.tgz", - "integrity": "sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", "license": "BSD-3-Clause" }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" }, "node_modules/selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "license": "MIT", "optional": true, "dependencies": { "parseley": "^0.12.0" @@ -14136,9 +14291,9 @@ } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -14148,24 +14303,29 @@ } }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "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.0", - "mime-types": "^3.0.1", + "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.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serialize-javascript": { @@ -14173,14 +14333,16 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "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", @@ -14189,17 +14351,24 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "devOptional": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -14211,6 +14380,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "devOptional": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -14232,6 +14403,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -14250,6 +14422,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -14265,6 +14438,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14282,6 +14456,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14299,12 +14474,15 @@ "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==" + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "devOptional": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -14312,32 +14490,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, "node_modules/sinon": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", - "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz", + "integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.0", - "@sinonjs/samsam": "^8.0.3", - "diff": "^8.0.2", + "@sinonjs/fake-timers": "^15.1.1", + "@sinonjs/samsam": "^9.0.3", + "diff": "^8.0.3", "supports-color": "^7.2.0" }, "funding": { @@ -14345,20 +14508,10 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/@sinonjs/fake-timers": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz", - "integrity": "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, "node_modules/sinon/node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -14370,6 +14523,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -14378,6 +14532,7 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "license": "MIT (http://mootools.net/license.txt)", "optional": true, "engines": { "node": "*" @@ -14388,10 +14543,21 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -14479,18 +14645,14 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -14505,23 +14667,11 @@ "node": ">=10" } }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14536,6 +14686,8 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14545,21 +14697,11 @@ "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14567,25 +14709,13 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14593,17 +14723,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -14614,20 +14733,11 @@ "node": ">=8" } }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -14638,6 +14748,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -14668,24 +14779,45 @@ "node": ">=0.8.0" } }, - "node_modules/strnum": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", - "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/stylehacks": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.8.tgz", + "integrity": "sha512-I3f053GBLIiS5Fg6OMFhq/c+yW+5Hc2+1fgq7gElDMMSqwlRb3tBf2ef6ucLStYRpId4q//bQO1FjcyNyy4yDQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "browserslist": "^4.28.1", + "postcss-selector-parser": "^7.1.1" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } }, "node_modules/super-regex": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-0.2.0.tgz", "integrity": "sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==", "dev": true, + "license": "MIT", "dependencies": { "clone-regexp": "^3.0.0", "function-timeout": "^0.1.0", @@ -14738,6 +14870,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -14749,6 +14882,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "optional": true, "engines": { "node": ">= 0.4" @@ -14757,6 +14891,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "license": "MIT", + "optional": true, + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=16" + } + }, "node_modules/swagger-ui-dist": { "version": "5.31.0", "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.31.0.tgz", @@ -14770,6 +14940,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", + "license": "MIT", "dependencies": { "swagger-ui-dist": ">=5.0.0" }, @@ -14806,30 +14977,10 @@ "url": "https://opencollective.com/synckit" } }, - "node_modules/table-layout": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", - "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", - "dependencies": { - "array-back": "^6.2.2", - "wordwrapjs": "^5.1.0" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "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": { @@ -14841,10 +14992,10 @@ } }, "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", - "dev": true, + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", + "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -14860,16 +15011,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -14967,14 +15117,14 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/terser/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -14984,7 +15134,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -15010,7 +15160,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -15039,6 +15189,7 @@ "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", "dev": true, + "license": "MIT", "dependencies": { "convert-hrtime": "^5.0.0" }, @@ -15052,7 +15203,8 @@ "node_modules/tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.15", @@ -15072,9 +15224,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15085,9 +15237,10 @@ } }, "node_modules/tlds": { - "version": "1.255.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", - "integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==", + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", + "license": "MIT", "optional": true, "bin": { "tlds": "bin.js" @@ -15097,13 +15250,15 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -15115,6 +15270,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -15123,12 +15279,32 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "license": "MIT", "optional": true }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/tr46": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", - "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", + "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" }, @@ -15141,6 +15317,7 @@ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -15178,9 +15355,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -15191,19 +15368,19 @@ } }, "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "version": "29.4.9", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.9.tgz", + "integrity": "sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==", "dev": true, "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", + "handlebars": "^4.7.9", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.3", + "semver": "^7.7.4", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -15220,7 +15397,7 @@ "babel-jest": "^29.0.0 || ^30.0.0", "jest": "^29.0.0 || ^30.0.0", "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" + "typescript": ">=4.3 <7" }, "peerDependenciesMeta": { "@babel/core": { @@ -15257,9 +15434,9 @@ } }, "node_modules/ts-loader": { - "version": "9.5.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", - "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", "dev": true, "license": "MIT", "dependencies": { @@ -15282,6 +15459,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -15321,10 +15499,11 @@ } }, "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -15334,6 +15513,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, + "license": "MIT", "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", @@ -15348,6 +15528,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.7.0", @@ -15363,6 +15544,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -15370,13 +15552,15 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -15389,15 +15573,16 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -15409,6 +15594,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -15419,9 +15605,10 @@ } }, "node_modules/typed-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", + "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", + "license": "MIT", "engines": { "node": ">= 18" } @@ -15436,7 +15623,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -15446,24 +15633,18 @@ "node": ">=14.17" } }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "engines": { - "node": ">=8" - } - }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT", "optional": true }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -15476,6 +15657,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "license": "MIT", "dependencies": { "@lukeed/csprng": "^1.0.0" }, @@ -15487,6 +15669,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", "dependencies": { "random-bytes": "~1.0.0" }, @@ -15494,19 +15677,32 @@ "node": ">= 0.8" } }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/undici": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", - "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "license": "MIT", + "optional": true, "engines": { "node": ">=18.17" } }, "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.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT" }, "node_modules/universalify": { @@ -15514,6 +15710,7 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -15563,10 +15760,10 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", - "dev": true, + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -15593,17 +15790,12 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", - "optional": true - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -15612,6 +15804,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -15620,12 +15813,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "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" } @@ -15638,6 +15833,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/esm/bin/uuid" } @@ -15646,7 +15842,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", @@ -15667,15 +15864,16 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "license": "MIT", "optional": true, "engines": { "node": ">=10" } }, "node_modules/validator": { - "version": "13.15.23", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", - "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -15685,6 +15883,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -15696,6 +15895,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "verror": "1.10.0" } @@ -15703,7 +15903,8 @@ "node_modules/vasync/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" }, "node_modules/vasync/node_modules/verror": { "version": "1.10.0", @@ -15712,6 +15913,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -15722,6 +15924,7 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -15734,27 +15937,29 @@ "node_modules/verror/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/wait-on": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.3.tgz", - "integrity": "sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.4.tgz", + "integrity": "sha512-k8qrgfwrPVJXTeFY8tl6BxVHiclK11u72DVKhpybHfUL/K6KM4bdyK9EhIVYGytB5MJe/3lq4Tf0hrjM+pvJZQ==", "dev": true, "license": "MIT", "dependencies": { - "axios": "^1.13.2", - "joi": "^18.0.1", - "lodash": "^4.17.21", + "axios": "^1.13.5", + "joi": "^18.0.2", + "lodash": "^4.17.23", "minimist": "^1.2.8", "rxjs": "^7.8.2" }, @@ -15770,14 +15975,15 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -15793,170 +15999,33 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/web-resource-inliner": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", - "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-8.0.0.tgz", + "integrity": "sha512-Ezr98sqXW/+OCGoUEXuOKVR+oVFlSdn1tIySEEJdiSAw4IjrW8hQkwARSSBJTSB5Us5dnytDgL0ZDliAYBhaNA==", + "license": "MIT", "optional": true, "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", - "htmlparser2": "^5.0.0", + "htmlparser2": "^9.1.0", "mime": "^2.4.6", - "node-fetch": "^2.6.0", "valid-data-url": "^3.0.0" }, "engines": { "node": ">=10.0.0" } }, - "node_modules/web-resource-inliner/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "optional": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/dom-serializer/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "optional": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "optional": true, - "dependencies": { - "domelementtype": "^2.0.1" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "optional": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domutils/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "optional": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "optional": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/htmlparser2": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", - "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", - "optional": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^3.3.0", - "domutils": "^2.4.2", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/fb55/htmlparser2?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "optional": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/web-resource-inliner/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "optional": true - }, - "node_modules/web-resource-inliner/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "optional": true - }, - "node_modules/web-resource-inliner/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "optional": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", "engines": { "node": ">= 8" } @@ -15965,14 +16034,15 @@ "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/webpack": { - "version": "5.104.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", - "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", + "version": "5.105.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", + "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "dev": true, "license": "MIT", "dependencies": { @@ -15982,11 +16052,11 @@ "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.4", + "enhanced-resolve": "^5.20.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -15998,9 +16068,9 @@ "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", - "watchpack": "^2.4.4", - "webpack-sources": "^3.3.3" + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" @@ -16023,14 +16093,15 @@ "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", "dev": true, "license": "MIT", "engines": { @@ -16060,6 +16131,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -16073,6 +16145,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -16082,6 +16155,7 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -16091,6 +16165,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -16118,10 +16193,48 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, "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" @@ -16134,6 +16247,8 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -16148,6 +16263,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", "dependencies": { "string-width": "^4.0.0" }, @@ -16156,13 +16272,13 @@ } }, "node_modules/winston": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", - "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", + "@dabh/diagnostics": "^2.0.8", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", @@ -16204,6 +16320,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "license": "MIT", "optional": true, "dependencies": { "@babel/parser": "^7.9.6", @@ -16220,6 +16337,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -16227,20 +16345,13 @@ "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" - }, - "node_modules/wordwrapjs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", - "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", - "engines": { - "node": ">=12.17" - } + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" }, "node_modules/workerpool": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", - "integrity": "sha512-Xz4Nm9c+LiBHhDR5bDLnNzmj6+5F+cyEAWPMkbs2awq/dYazR/efelZzUAjB/y3kNHL+uzkHvxVVpaOfGCPV7A==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, @@ -16264,6 +16375,8 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -16276,34 +16389,11 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", @@ -16319,20 +16409,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "devOptional": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -16349,6 +16431,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "devOptional": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -16367,6 +16450,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "devOptional": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -16376,6 +16460,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -16391,6 +16476,7 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -16400,6 +16486,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 0f48c6701..f97256409 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", "start:test": "dotenv -o -e test/config/.env -e test/config/.env.override -- npm run start", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"", - "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "lint": "eslint \"src/**/*.ts\"", + "lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.js\" --fix", "test": "jest", "test:watch": "jest --watch --maxWorkers=25%", "test:cov": "jest --coverage --maxWorkers=50%", @@ -30,18 +30,16 @@ "test:api": "npm run test:api:jest --maxWorkers=50% && concurrently -k -s first \"wait-on http://localhost:3000/explorer/ && npm run test:api:mocha\" \"npm run start:test\"", "test:api:jest": "dotenv -o -e test/config/.env -e test/config/.env.override -- jest --config ./test/config/jest-e2e.json --maxWorkers=50%", "test:api:mocha": "dotenv -o -e test/config/.env -e test/config/.env.override -- mocha --config ./test/config/.mocharc.js -r chai/register-should.js", - "prepare:local": "docker-compose -f CI/E2E/docker-compose-local.yaml --env-file CI/E2E/.env.elastic-search up -d && cp test/config/functionalAccounts.json functionalAccounts.json && cp proposalTypes.example.json proposalTypes.json && cp publishedDataConfig.example.json publishedDataConfig.json" + "prepare:local": "docker-compose -f CI/E2E/docker-compose-local.yaml up -d && cp test/config/functionalAccounts.json functionalAccounts.json && cp proposalTypes.example.json proposalTypes.json && cp publishedDataConfig.example.json publishedDataConfig.json" }, "dependencies": { "@casl/ability": "^6.3.2", "@casl/mongoose": "^8.0.4", - "@elastic/elasticsearch": "^8.15.0", "@nestjs-modules/mailer": "^2", "@nestjs/axios": "^4", "@nestjs/common": "^11", "@nestjs/config": "^4", "@nestjs/core": "^11", - "@nestjs/elasticsearch": "^11", "@nestjs/event-emitter": "^3", "@nestjs/jwt": "^11", "@nestjs/mongoose": "^11.0.4", @@ -49,15 +47,19 @@ "@nestjs/platform-express": "^11", "@nestjs/swagger": "^11.1.1", "@nestjs/terminus": "^11", + "@nestjs/throttler": "^6.5.0", + "@opensearch-project/opensearch": "^3.5.1", "@types/json-merge-patch": "^1.0.0", "@types/jsonschema": "^1.1.1", "@user-office-software/duo-logger": "^2.1.1", "@user-office-software/duo-message-broker": "^1.4.0", - "ajv": "^8.12.0", - "amqplib": "^0.10.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", + "amqplib": "^1.0.2", "bcrypt": "^6.0.0", "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", + "class-validator": "^0.15.1", "connect-mongo": "^6.0.0", "dotenv": "^17.2.0", "express-session": "^1.17.3", @@ -89,7 +91,8 @@ }, "socks": { "ip": "^2.0.2" - } + }, + "mongodb": "6.20.0" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -115,7 +118,7 @@ "@types/nodemailer": "^7.0.1", "@types/passport-jwt": "^4.0.0", "@types/passport-local": "^1.0.34", - "@types/supertest": "^6.0.1", + "@types/supertest": "^7.2.0", "@types/uuid": "^11.0.0", "@typescript-eslint/eslint-plugin": "^8.1.0", "@typescript-eslint/parser": "^8.1.0", @@ -123,7 +126,7 @@ "chai-http": "^5.1.1", "concurrently": "^9.0.0", "dotenv-cli": "^11.0.0", - "eslint": "^9.0.0", + "eslint": "^10.0.3", "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.0.0", "globals": "^17.0.0", diff --git a/publishedDataConfig.example.json b/publishedDataConfig.example.json index 6d09b4286..ab4458dad 100644 --- a/publishedDataConfig.example.json +++ b/publishedDataConfig.example.json @@ -1,6 +1,7 @@ { "metadataSchema": { "type": "object", + "dynamicDefaults": { "publicationYear": "currentYear" }, "properties": { "creators": { "type": "array", diff --git a/src/app.module.ts b/src/app.module.ts index 054d8066a..1295cbfae 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -22,7 +22,7 @@ import { JobsModule } from "./jobs/jobs.module"; import { InstrumentsModule } from "./instruments/instruments.module"; import { MailerModule } from "@nestjs-modules/mailer"; import { join } from "path"; -import { HandlebarsAdapter } from "@nestjs-modules/mailer/dist/adapters/handlebars.adapter"; +import { HandlebarsAdapter } from "@nestjs-modules/mailer/adapters/handlebars.adapter"; import { handlebarsHelpers } from "./common/handlebars-helpers"; import { CommonModule } from "./common/common.module"; import { RabbitMQModule } from "./common/rabbitmq/rabbitmq.module"; @@ -43,6 +43,9 @@ import { import { HistoryModule } from "./history/history.module"; import { MaskSensitiveDataInterceptorModule } from "./common/interceptors/mask-sensitive-data.interceptor"; import { RuntimeConfigModule } from "./config/runtime-config/runtime-config.module"; +import { MetadataKeysModule } from "./metadata-keys/metadatakeys.module"; +import { OidcClientModule } from "./common/openid-client/openid-client.module"; +import { ThrottlerModule } from "@nestjs/throttler"; @Module({ imports: [ @@ -51,8 +54,8 @@ import { RuntimeConfigModule } from "./config/runtime-config/runtime-config.modu isGlobal: true, cache: true, }), - RuntimeConfigModule, AuthModule, + OidcClientModule, CaslModule, AttachmentsModule, CommonModule, @@ -70,6 +73,8 @@ import { RuntimeConfigModule } from "./config/runtime-config/runtime-config.modu DatasetsModule, InitialDatasetsModule, InstrumentsModule, + MetadataKeysModule, + RuntimeConfigModule, JobsModule, LogbooksModule, EventEmitterModule.forRoot(), @@ -162,6 +167,15 @@ import { RuntimeConfigModule } from "./config/runtime-config/runtime-config.modu MaskSensitiveDataInterceptorModule, (env: NodeJS.ProcessEnv) => env.MASK_PERSONAL_INFO === "yes", ), + ThrottlerModule.forRoot({ + throttlers: [ + { + name: "login", + ttl: 1000, + limit: 1, + }, + ], + }), ], controllers: [], providers: [ diff --git a/src/attachments/attachments.v4.controller.spec.ts b/src/attachments/attachments.v4.controller.spec.ts index df06a21e7..97632a30f 100644 --- a/src/attachments/attachments.v4.controller.spec.ts +++ b/src/attachments/attachments.v4.controller.spec.ts @@ -7,6 +7,7 @@ import { Attachment } from "./schemas/attachment.schema"; import * as jmp from "json-merge-patch"; import { CaslAbilityFactory } from "src/casl/casl-ability.factory"; import { PoliciesGuard } from "src/casl/guards/policies.guard"; +import { Request } from "express"; describe("AttachmentsController - findOneAndUpdate", () => { let controller: AttachmentsV4Controller; @@ -14,15 +15,22 @@ describe("AttachmentsController - findOneAndUpdate", () => { const mockAttachment: Attachment = { _id: "123", - name: "Test Attachment", - description: "Initial", + aid: "aid-123", + ownerGroup: "group1", + accessGroups: ["group1"], + isPublished: false, + thumbnail: "Test Attachment", + caption: "Test Caption", + createdBy: "user1", + updatedBy: "user1", + createdAt: new Date("2025-08-01T10:00:00Z"), updatedAt: new Date("2025-09-01T10:00:00Z"), // other fields... }; const mockUpdatedAttachment = { ...mockAttachment, - description: "Updated", + caption: "Updated", }; const mockCaslAbilityFactory = { @@ -31,10 +39,6 @@ describe("AttachmentsController - findOneAndUpdate", () => { }), }; - const mockAttachmentsV4Service = { - findOneAndUpdate: jest.fn(), - }; - beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [AttachmentsV4Controller], @@ -60,25 +64,30 @@ describe("AttachmentsController - findOneAndUpdate", () => { // Mock permission check jest - .spyOn(controller, "checkPermissionsForAttachment") + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .spyOn(controller as any, "checkPermissionsForAttachment") .mockResolvedValue(mockAttachment); }); it("should update attachment with application/json", async () => { - const dto: PartialUpdateAttachmentV4Dto = { description: "Updated" }; - const headers = { "content-type": "application/json" }; + const dto: PartialUpdateAttachmentV4Dto = { caption: "Updated" }; - const result = await controller.findOneAndUpdate({ headers }, "123", dto); + const req = { + headers: { "content-type": "application/json" }, + } as Partial as Request; + const result = await controller.findOneAndUpdate(req, "123", dto); expect(result).toEqual(mockUpdatedAttachment); expect(service.findOneAndUpdate).toHaveBeenCalledWith({ _id: "123" }, dto); }); it("should update attachment with application/merge-patch+json", async () => { - const dto = { description: null }; - const headers = { "content-type": "application/merge-patch+json" }; + const dto = { caption: "Updated" }; + const req = { + headers: { "content-type": "application/merge-patch+json" }, + } as Partial as Request; - await controller.findOneAndUpdate({ headers }, "123", dto); + await controller.findOneAndUpdate(req, "123", dto); const expectedPatched = jmp.apply(mockAttachment, dto); expect(service.findOneAndUpdate).toHaveBeenCalledWith( @@ -88,15 +97,16 @@ describe("AttachmentsController - findOneAndUpdate", () => { }); it("should throw PRECONDITION_FAILED if If-Unmodified-Since is older than updatedAt", async () => { - const dto = { name: "Should Fail" }; - const headers = { - "content-type": "application/json", - "if-unmodified-since": "2000-01-01T00:00:00Z", - }; - - await expect( - controller.findOneAndUpdate({ headers }, "123", dto), - ).rejects.toThrow( + const dto = { caption: "Should Fail" }; + + const req = { + headers: { + "content-type": "application/json", + "if-unmodified-since": "2000-01-01T00:00:00Z", + }, + } as Partial as Request; + + await expect(controller.findOneAndUpdate(req, "123", dto)).rejects.toThrow( new HttpException( "Resource has been modified on server", HttpStatus.PRECONDITION_FAILED, diff --git a/src/attachments/attachments.v4.controller.ts b/src/attachments/attachments.v4.controller.ts index 5844510ad..ad85f69e0 100644 --- a/src/attachments/attachments.v4.controller.ts +++ b/src/attachments/attachments.v4.controller.ts @@ -40,7 +40,6 @@ import { IAttachmentFiltersV4, } from "./interfaces/attachment-filters.interface"; -import { OutputDatasetDto } from "src/datasets/dto/output-dataset.dto"; import { getSwaggerAttachmentFilterContent } from "./types/attachment-filter-contents"; import { FilterValidationPipe } from "src/common/pipes/filter-validation.pipe"; import { CreateAttachmentV4Dto } from "./dto/create-attachment.v4.dto"; @@ -232,7 +231,7 @@ export class AttachmentsV4Controller { }) @ApiResponse({ status: HttpStatus.OK, - type: OutputDatasetDto, + type: OutputAttachmentV4Dto, isArray: true, description: "Return the attachments requested", }) @@ -279,7 +278,7 @@ export class AttachmentsV4Controller { }) @ApiResponse({ status: HttpStatus.OK, - type: OutputDatasetDto, + type: OutputAttachmentV4Dto, isArray: true, description: "Return the attachments requested", }) @@ -324,7 +323,7 @@ export class AttachmentsV4Controller { }) @ApiResponse({ status: HttpStatus.OK, - type: Attachment, + type: OutputAttachmentV4Dto, description: "Return attachment with id specified", }) @Get("/:aid") diff --git a/src/auth/access-group-provider/access-group-from-graphql-api-call.service.ts b/src/auth/access-group-provider/access-group-from-graphql-api-call.service.ts index 0d29f28f2..b0bd1d032 100644 --- a/src/auth/access-group-provider/access-group-from-graphql-api-call.service.ts +++ b/src/auth/access-group-provider/access-group-from-graphql-api-call.service.ts @@ -2,9 +2,9 @@ import { AccessGroupService as AccessGroupService } from "./access-group.service import { Injectable, Logger } from "@nestjs/common"; ///import fetch from "node-fetch"; -import { UserPayload } from "../interfaces/userPayload.interface"; import { HttpService } from "@nestjs/axios"; import { firstValueFrom } from "rxjs"; +import { UserPayload } from "src/auth/interfaces/userPayload.interface"; /** * This service is used to fetch access groups from a GraphQL API. */ diff --git a/src/auth/access-group-provider/access-group-from-multiple-providers.service.ts b/src/auth/access-group-provider/access-group-from-multiple-providers.service.ts index 60cf7f289..0c932e39b 100644 --- a/src/auth/access-group-provider/access-group-from-multiple-providers.service.ts +++ b/src/auth/access-group-provider/access-group-from-multiple-providers.service.ts @@ -1,6 +1,6 @@ import { Injectable } from "@nestjs/common"; -import { UserPayload } from "../interfaces/userPayload.interface"; import { AccessGroupService } from "./access-group.service"; +import { UserPayload } from "src/auth/interfaces/userPayload.interface"; /** * This service is used to get the access groups from multiple providers. diff --git a/src/auth/access-group-provider/access-group-from-payload.service.ts b/src/auth/access-group-provider/access-group-from-payload.service.ts index e36f5a87a..bc07ebb42 100644 --- a/src/auth/access-group-provider/access-group-from-payload.service.ts +++ b/src/auth/access-group-provider/access-group-from-payload.service.ts @@ -1,8 +1,8 @@ //import { AccessGroupService as AccessGroupService } from "./access-group.service"; import { Injectable, Logger } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; -import { UserPayload } from "../interfaces/userPayload.interface"; import { AccessGroupService } from "./access-group.service"; +import { UserPayload } from "src/auth/interfaces/userPayload.interface"; /** * This service is used to get the access groups from the payload of the IDP. diff --git a/src/auth/access-group-provider/access-group-from-rest-api-call.service.spec.ts b/src/auth/access-group-provider/access-group-from-rest-api-call.service.spec.ts new file mode 100644 index 000000000..c38a0e8b5 --- /dev/null +++ b/src/auth/access-group-provider/access-group-from-rest-api-call.service.spec.ts @@ -0,0 +1,46 @@ +import { HttpService } from "@nestjs/axios"; +import { Test, TestingModule } from "@nestjs/testing"; +import { UserPayload } from "../interfaces/userPayload.interface"; +import { AccessGroupFromRestApiService } from "./access-group-from-rest-api-call.service"; + +describe("AccessGroupFromRestApiService", () => { + const mockResponse = ["AAA", "BBB"]; + + let service: AccessGroupFromRestApiService; + const mockAccessGroupService = new AccessGroupFromRestApiService( + "", + {}, + "payload.id", + new HttpService(), + ); + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [AccessGroupFromRestApiService], + }) + .overrideProvider(AccessGroupFromRestApiService) + .useValue(mockAccessGroupService) + .compile(); + + service = module.get( + AccessGroupFromRestApiService, + ); + + jest.spyOn(service, "callRestApi").mockImplementation(async () => { + return mockResponse; + }); + }); + + it("should be defined", () => { + expect(service).toBeDefined(); + }); + + it("Should resolve access groups", async () => { + const expected = ["AAA", "BBB"]; + const actual = await service.getAccessGroups({ + userId: "12378", + payload: { id: "123" }, + } as UserPayload); + expect(actual).toEqual(expected); + }); +}); diff --git a/src/auth/access-group-provider/access-group-from-rest-api-call.service.ts b/src/auth/access-group-provider/access-group-from-rest-api-call.service.ts new file mode 100644 index 000000000..c46a78f8a --- /dev/null +++ b/src/auth/access-group-provider/access-group-from-rest-api-call.service.ts @@ -0,0 +1,69 @@ +import { AccessGroupService as AccessGroupService } from "./access-group.service"; +import { Injectable, Logger } from "@nestjs/common"; +///import fetch from "node-fetch"; + +import { UserPayload } from "../interfaces/userPayload.interface"; +import { HttpService } from "@nestjs/axios"; +import { firstValueFrom } from "rxjs"; +import { get } from "lodash"; +import { AxiosError } from "axios"; +/** + * This service is used to fetch access groups from a REST API. + */ +@Injectable() +export class AccessGroupFromRestApiService extends AccessGroupService { + constructor( + private apiUrl: string, + private headers: Record, + private userIdfield: string, + private readonly httpService: HttpService, + ) { + super(); + } + + async getAccessGroups(userPayload: UserPayload): Promise { + const userId = get(userPayload, this.userIdfield) as string; + if (!userId) { + Logger.error(`User ID not found in payload: ${this.userIdfield}`); + return []; + } + const url = this.apiUrl.replace("{userId}", userId); + + const responseData = await this.callRestApi(url); + if (!responseData) { + Logger.warn("No access groups returned from REST API"); + return []; + } + return responseData; + } + + async callRestApi(url: string): Promise { + try { + const response = await firstValueFrom( + this.httpService.get(url, { + headers: { + ...this.headers, + }, + }), + ); + + if (!response || !response.data) { + Logger.warn("No access groups returned from REST API"); + return []; + } + + return response.data; + } catch (err: unknown) { + if (err instanceof AxiosError) { + Logger.warn( + `Status: ${err.response?.status}, Body: ${JSON.stringify(err.response?.data)}`, + ); + } else if (err instanceof Error) { + Logger.error(err.message); + } else { + Logger.error("Unknown error occurred"); + } + return []; + } + } +} diff --git a/src/auth/access-group-provider/access-group-service-factory.ts b/src/auth/access-group-provider/access-group-service-factory.ts index 6c9f7c689..91c48fe69 100644 --- a/src/auth/access-group-provider/access-group-service-factory.ts +++ b/src/auth/access-group-provider/access-group-service-factory.ts @@ -3,6 +3,7 @@ import { AccessGroupFromStaticValuesService } from "./access-group-from-static-v import { AccessGroupService } from "./access-group.service"; import { AccessGroupFromGraphQLApiService } from "./access-group-from-graphql-api-call.service"; import { AccessGroupFromPayloadService } from "./access-group-from-payload.service"; +import { AccessGroupFromRestApiService } from "./access-group-from-rest-api-call.service"; import { HttpService } from "@nestjs/axios"; import { AccessGroupFromMultipleProvidersService } from "./access-group-from-multiple-providers.service"; import { Logger } from "@nestjs/common"; @@ -23,6 +24,8 @@ export const accessGroupServiceFactory = { "accessGroupsOIDCPayloadConfig", ); + const accessGroupsRestConfig = configService.get("accessGroupsRestConfig"); + const accessGroupServices: AccessGroupService[] = []; if (accessGroupsStaticConfig?.enabled == true) { Logger.log( @@ -70,6 +73,23 @@ export const accessGroupServiceFactory = { }, ); } + if (accessGroupsRestConfig?.enabled == true) { + Logger.log( + JSON.stringify(accessGroupsRestConfig), + "loading REST API processor", + ); + accessGroupServices.push( + new AccessGroupFromRestApiService( + accessGroupsRestConfig.apiUrl, + { + [accessGroupsRestConfig.authKey]: + accessGroupsRestConfig.token.trim(), + }, + accessGroupsRestConfig.userIdField || "userId", + new HttpService(), + ), + ); + } return new AccessGroupFromMultipleProvidersService(accessGroupServices); }, diff --git a/src/auth/access-group-provider/access-group.service.ts b/src/auth/access-group-provider/access-group.service.ts index c29b7da54..055a02c25 100644 --- a/src/auth/access-group-provider/access-group.service.ts +++ b/src/auth/access-group-provider/access-group.service.ts @@ -1,4 +1,4 @@ -import { UserPayload } from "../interfaces/userPayload.interface"; +import { UserPayload } from "src/auth/interfaces/userPayload.interface"; export abstract class AccessGroupService { abstract getAccessGroups( diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts index da0bc005d..57eac5474 100644 --- a/src/auth/auth.controller.spec.ts +++ b/src/auth/auth.controller.spec.ts @@ -4,6 +4,7 @@ import { AuthService } from "./auth.service"; import { Response } from "express"; import { Session } from "express-session"; import { ConfigService } from "@nestjs/config"; +import { ThrottlerModule } from "@nestjs/throttler"; class AuthServiceMock { login() { @@ -29,6 +30,17 @@ describe("AuthController", () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ + imports: [ + ThrottlerModule.forRoot({ + throttlers: [ + { + name: "login", + ttl: 1000, + limit: 1, + }, + ], + }), + ], controllers: [AuthController], providers: [ ConfigService, diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 88e868804..8ef18d690 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -6,6 +6,7 @@ import { Res, Req, HttpCode, + Body, } from "@nestjs/common"; import { LocalAuthGuard } from "./guards/local-auth.guard"; import { AuthService } from "./auth.service"; @@ -17,6 +18,7 @@ import { ApiResponse, ApiTags, ApiQuery, + ApiOkResponse, } from "@nestjs/swagger"; import { CredentialsDto } from "./dto/credentials.dto"; import { LdapAuthGuard } from "./guards/ldap.guard"; @@ -25,6 +27,8 @@ import { User } from "src/users/schemas/user.schema"; import { OidcAuthGuard } from "./guards/oidc.guard"; import { Request, Response } from "express"; import { ReturnedAuthLoginDto } from "./dto/returnedLogin.dto"; +import { IdTokenDto } from "./dto/idToken.dto"; +import { ThrottlerGuard } from "@nestjs/throttler"; @ApiBearerAuth() @ApiTags("auth") @@ -91,6 +95,21 @@ export class AuthController { // this function is invoked when the oidc is set as an auth method. It's behaviour comes from the oidc strategy } + @AllowAny() + @UseGuards(ThrottlerGuard) + @ApiBody({ type: IdTokenDto }) + @ApiOkResponse({ + description: + "Successfully authenticated via OIDC. Returns SciCat access token.", + type: ReturnedAuthLoginDto, + }) + @Post("oidc/token") + async oidcTokenLogin( + @Body() idTokenDto: IdTokenDto, + ): Promise { + return this.authService.oidcTokenLogin(idTokenDto.idToken); + } + @AllowAny() @UseGuards(OidcAuthGuard) @Get("oidc/callback") diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index b6cb1eccc..3f9747d1d 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -8,37 +8,31 @@ import { JwtModule } from "@nestjs/jwt"; import { JwtStrategy } from "./strategies/jwt.strategy"; import { LdapStrategy } from "./strategies/ldap.strategy"; import { ConfigService } from "@nestjs/config"; -import { UsersService } from "src/users/users.service"; import { OidcConfig } from "src/config/configuration"; -import { BuildOpenIdClient, OidcStrategy } from "./strategies/oidc.strategy"; +import { OidcStrategy } from "./strategies/oidc.strategy"; import { accessGroupServiceFactory } from "./access-group-provider/access-group-service-factory"; -import { AccessGroupService } from "./access-group-provider/access-group.service"; import { CaslModule } from "src/casl/casl.module"; import { SessionMiddleware } from "./middlewares/session.middleware"; +import { OidcClientService } from "../common/openid-client/openid-client.service"; +import { OidcAuthService } from "src/common/openid-client/openid-auth.service"; const OidcStrategyFactory = { provide: "OidcStrategy", useFactory: async ( - authService: AuthService, + oidcClientService: OidcClientService, + oidcAuthService: OidcAuthService, configService: ConfigService, - userService: UsersService, - accessGroupService: AccessGroupService, ) => { if (!configService.get("oidc")?.issuer) { return null; } - const clientBuilder = new BuildOpenIdClient(configService); - const client = await clientBuilder.build(); - const strategy = new OidcStrategy( - authService, - client, - configService, - userService, - accessGroupService, - ); + + const client = await oidcClientService.getClient(); + + const strategy = new OidcStrategy(client, configService, oidcAuthService); return strategy; }, - inject: [AuthService, ConfigService, UsersService, AccessGroupService], + inject: [OidcClientService, OidcAuthService, ConfigService], }; @Module({ diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index fb8afe31e..61d0d1768 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -3,13 +3,31 @@ import { JwtService } from "@nestjs/jwt"; import { Test, TestingModule } from "@nestjs/testing"; import { UsersService } from "src/users/users.service"; import { AuthService } from "./auth.service"; +import { OidcClientService } from "src/common/openid-client/openid-client.service"; +import { OidcAuthService } from "src/common/openid-client/openid-auth.service"; -class JwtServiceMock {} +class JwtServiceMock { + sign = jest.fn(); +} -class UsersServiceMock {} +class UsersServiceMock { + findByIdUserSettings = jest.fn().mockResolvedValue({}); + createUserSettings = jest.fn().mockResolvedValue({}); +} +class OidcClientServiceMock { + getClient = jest.fn(); +} + +class OidcAuthServiceMock { + validate = jest.fn(); +} describe("AuthService", () => { let authService: AuthService; + let oidcClientService: OidcClientServiceMock; + let oidcAuthService: OidcAuthServiceMock; + let jwtService: JwtServiceMock; + let configService: ConfigService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -18,13 +36,50 @@ describe("AuthService", () => { ConfigService, { provide: JwtService, useClass: JwtServiceMock }, { provide: UsersService, useClass: UsersServiceMock }, + { provide: OidcClientService, useClass: OidcClientServiceMock }, + { provide: OidcAuthService, useClass: OidcAuthServiceMock }, ], }).compile(); authService = module.get(AuthService); + oidcClientService = module.get(OidcClientService); + oidcAuthService = module.get(OidcAuthService); + jwtService = module.get(JwtService); + configService = module.get(ConfigService); }); it("should be defined", () => { expect(authService).toBeDefined(); }); + + describe("Oidc Token Login", () => { + const mockIdToken = "valid-id-token"; + const mockUser = { _id: "user_123", email: "test@example.com" }; + const mockAccessToken = "signed-jwt-token"; + const mockExpiresIn = 3600; + + it("should successfully validate token and return auth login dto", async () => { + const postLoginSpy = jest.spyOn(authService, "postLoginTasks"); + + const mockClient = { + callback: jest.fn().mockResolvedValue({ id_token: mockIdToken }), + }; + oidcClientService.getClient.mockResolvedValue(mockClient); + + jest.spyOn(configService, "get").mockImplementation((key: string) => { + if (key === "oidc.callbackURL") return "http://localhost/callback"; + if (key === "jwt.expiresIn") return mockExpiresIn; + return null; + }); + + oidcAuthService.validate.mockResolvedValue(mockUser); + jwtService.sign.mockReturnValue(mockAccessToken); + + const result = await authService.oidcTokenLogin(mockIdToken); + + expect(result.access_token).toBe(mockAccessToken); + expect(result.userId).toBe(mockUser._id); + expect(postLoginSpy).toHaveBeenCalledWith(mockUser); + }); + }); }); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 25f565d9c..d403fab7f 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,4 +1,10 @@ -import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common"; +import { + HttpException, + HttpStatus, + Injectable, + Logger, + UnauthorizedException, +} from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { JwtService } from "@nestjs/jwt"; import { compare } from "bcrypt"; @@ -7,16 +13,20 @@ import { UsersService } from "../users/users.service"; import { Request } from "express"; import { OidcConfig } from "src/config/configuration"; import { flattenObject, parseBoolean } from "src/common/utils"; -import { Issuer } from "openid-client"; +import { Issuer, TokenSet } from "openid-client"; import { ReturnedAuthLoginDto } from "./dto/returnedLogin.dto"; import { ReturnedUserDto } from "src/users/dto/returned-user.dto"; import { CreateUserSettingsDto } from "src/users/dto/create-user-settings.dto"; +import { OidcClientService } from "../common/openid-client/openid-client.service"; +import { OidcAuthService } from "src/common/openid-client/openid-auth.service"; @Injectable() export class AuthService { constructor( private configService: ConfigService, private usersService: UsersService, + private oidcClientService: OidcClientService, + private oidcAuthService: OidcAuthService, private jwtService: JwtService, ) {} @@ -56,6 +66,34 @@ export class AuthService { }; } + async oidcTokenLogin(idToken: string): Promise { + let tokenSet: TokenSet; + const client = await this.oidcClientService.getClient(); + const callbackUrl = this.configService.get("oidc.callbackURL"); + + try { + tokenSet = await client.callback(callbackUrl, { id_token: idToken }, {}); + } catch (error) { + throw new UnauthorizedException( + `Invalid idToken: ${(error as Error).message}`, + ); + } + const user = await this.oidcAuthService.validate(tokenSet); + const expiresIn = this.configService.get("jwt.expiresIn"); + const accessToken = this.jwtService.sign(user, { expiresIn }); + await this.postLoginTasks(user); + + return { + access_token: accessToken, + id: accessToken, + expires_in: expiresIn, + ttl: expiresIn, + created: new Date().toISOString(), + userId: user._id, + user: user as ReturnedUserDto, + }; + } + async logout(req: Request) { const logoutURL = this.configService.get("logoutURL") || ""; const expressSessionSecret = this.configService.get( diff --git a/src/auth/dto/idToken.dto.ts b/src/auth/dto/idToken.dto.ts new file mode 100644 index 000000000..7f4a1ac00 --- /dev/null +++ b/src/auth/dto/idToken.dto.ts @@ -0,0 +1,16 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsString } from "class-validator"; + +export class IdTokenDto { + @ApiProperty({ + required: true, + description: + "OpenID Connect ID Token issued by the external identity provider for SciCat user authentication. " + + "The token must contain the user's identity claims (e.g., subject, email, name) and is verified " + + "by the backend to authenticate the user and generate a SciCat JWT access token.", + example: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + }) + @IsString() + @IsNotEmpty() + readonly idToken: string; +} diff --git a/src/auth/strategies/ldap.strategy.ts b/src/auth/strategies/ldap.strategy.ts index 1aab8bed3..babbbd171 100644 --- a/src/auth/strategies/ldap.strategy.ts +++ b/src/auth/strategies/ldap.strategy.ts @@ -16,7 +16,7 @@ import { LdapConfig } from "src/config/configuration"; @Injectable() export class LdapStrategy extends PassportStrategy(Strategy, "ldap") { constructor( - private configService: ConfigService, + configService: ConfigService, private usersService: UsersService, private accessGroupService: AccessGroupService, ) { diff --git a/src/auth/strategies/local.strategy.ts b/src/auth/strategies/local.strategy.ts index da8452632..dcab0cf03 100644 --- a/src/auth/strategies/local.strategy.ts +++ b/src/auth/strategies/local.strategy.ts @@ -15,7 +15,6 @@ export class LocalStrategy extends PassportStrategy(Strategy) { constructor( private authService: AuthService, private rolesService: RolesService, - //private configService: ConfigService, private usersService: UsersService, private accessGroupService: AccessGroupService, ) { diff --git a/src/auth/strategies/oidc.strategy.ts b/src/auth/strategies/oidc.strategy.ts index 974e36b8a..c19f85a10 100644 --- a/src/auth/strategies/oidc.strategy.ts +++ b/src/auth/strategies/oidc.strategy.ts @@ -1,66 +1,20 @@ -import { - Injectable, - Logger, - InternalServerErrorException, -} from "@nestjs/common"; +import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { PassportStrategy } from "@nestjs/passport"; -import { FilterQuery } from "mongoose"; -import { CreateUserIdentityDto } from "src/users/dto/create-user-identity.dto"; -import { CreateUserDto } from "src/users/dto/create-user.dto"; -import { User, UserDocument, UserSchema } from "src/users/schemas/user.schema"; -import { UsersService } from "src/users/users.service"; -import { - Strategy, - Client, - TokenSet, - Issuer, - IdTokenClaims, - UserinfoResponse, -} from "openid-client"; -import { AuthService } from "../auth.service"; -import { Profile } from "passport"; -import { UserProfile } from "src/users/schemas/user-profile.schema"; -import { OidcConfig } from "src/config/configuration"; -import { AccessGroupService } from "../access-group-provider/access-group.service"; -import { UserPayload } from "../interfaces/userPayload.interface"; -import { - IOidcUserInfoMapping, - IOidcUserQueryMapping, -} from "../interfaces/oidc-user.interface"; - -type extendedIdTokenClaims = IdTokenClaims & - UserinfoResponse & { - groups?: string[]; - }; -type OidcProfile = Profile & UserProfile; -export class BuildOpenIdClient { - constructor(private configService: ConfigService) {} - async build() { - const oidcConfig = this.configService.get("oidc"); - const trustIssuer = await Issuer.discover( - `${oidcConfig?.issuer}/.well-known/openid-configuration`, - ); - const client = new trustIssuer.Client({ - client_id: oidcConfig?.clientID as string, - client_secret: oidcConfig?.clientSecret as string, - }); - return client; - } -} +import { User } from "src/users/schemas/user.schema"; +import { Strategy, Client, TokenSet } from "openid-client"; +import { OidcConfig } from "src/config/configuration"; +import { OidcAuthService } from "src/common/openid-client/openid-auth.service"; @Injectable() export class OidcStrategy extends PassportStrategy(Strategy, "oidc") { - client: Client; authStrategy = "oidc"; constructor( - private readonly authService: AuthService, client: Client, - private configService: ConfigService, - private usersService: UsersService, - private accessGroupService: AccessGroupService, + configService: ConfigService, + private oidcAuthService: OidcAuthService, ) { const oidcConfig = configService.get("oidc"); super({ @@ -72,195 +26,9 @@ export class OidcStrategy extends PassportStrategy(Strategy, "oidc") { passReqToCallback: false, usePKCE: false, }); - - this.client = client; } async validate(tokenset: TokenSet): Promise> { - const userinfo: extendedIdTokenClaims = tokenset.claims(); - - const oidcConfig = this.configService.get("oidc"); - - const userProfile = this.parseUserInfo(userinfo); - - const userPayload: UserPayload = { - userId: userProfile.id, - username: userProfile.username, - email: userProfile.email, - accessGroupProperty: oidcConfig?.accessGroupProperty, - payload: userinfo, - }; - userProfile.accessGroups = - await this.accessGroupService.getAccessGroups(userPayload); - - const userFilter: FilterQuery = - this.parseQueryFilter(userProfile); - - let user = await this.usersService.findOne(userFilter); - - if (!user) { - const createUser: CreateUserDto = { - username: userProfile.username, - email: userProfile.email as string, - authStrategy: "oidc", - }; - - const newUser = await this.usersService.create(createUser); - if (!newUser) { - throw new InternalServerErrorException( - "Could not create User from OIDC response.", - ); - } - Logger.log("Created oidc user ", newUser.username); - - const createUserIdentity: CreateUserIdentityDto = { - authStrategy: "oidc", - credentials: {}, - externalId: userProfile.id, - profile: userProfile, - provider: userProfile.provider || "oidc", - userId: newUser._id, - }; - - await this.usersService.createUserIdentity(createUserIdentity); - Logger.log("Created user identity for oidc user with id ", newUser._id); - - user = newUser; - } else { - await this.usersService.updateUser( - { username: userProfile.username }, - user._id, - ); - await this.usersService.updateUserIdentity( - { - profile: userProfile, - externalId: userProfile.id, - provider: userProfile.provider || "oidc", - }, - user._id, - ); - } - - const jsonUser = JSON.parse(JSON.stringify(user)); - const { ...returnUser } = jsonUser; - returnUser.userId = returnUser._id; - - return returnUser; - } - - getUserPhoto(thumbnailPhoto: string) { - return thumbnailPhoto - ? "data:image/jpeg;base64," + - Buffer.from(thumbnailPhoto, "binary").toString("base64") - : "no photo"; - } - - parseUserInfo(userinfo: extendedIdTokenClaims) { - const profile = {} as OidcProfile; - - const customUserInfoFields = this.configService.get( - "oidc.userInfoMapping", - ); - - // To dynamically map user info fields based on environment variables, - // set mappings like OIDC_USERINFO_MAPPING_FIELD_USERNAME=family_name. - // This assigns userinfo.family_name to oidcUser.username. - - const oidcUser: IOidcUserInfoMapping = { - id: userinfo["sub"] ?? (userinfo["user_id"] as string) ?? "", - username: userinfo["preferred_username"] ?? userinfo["name"] ?? "", - displayName: userinfo["name"] ?? "", - familyName: userinfo["family_name"] ?? "", - email: userinfo["email"] ?? "", - thumbnailPhoto: (userinfo["thumbnailPhoto"] as string) ?? "", - provider: userinfo["iss"] ?? "", - groups: userinfo["groups"] ?? [], - }; - - if (customUserInfoFields) { - Object.entries(customUserInfoFields).forEach( - ([sourceField, targetField]) => { - if (typeof targetField === "string" && targetField in userinfo) { - oidcUser[sourceField] = userinfo[targetField] as string; - } else if (Array.isArray(targetField) && targetField.length) { - const values = targetField - .filter((field) => field in userinfo) - .map((field) => userinfo[field] as string); - - if (values.length) { - oidcUser[sourceField] = values.join("_"); - } - } - }, - ); - } - - // Prior to OpenID Connect Basic Client Profile 1.0 - draft 22, the "sub" - // claim was named "user_id". Many providers still use the old name, so - // fallback to that. https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims - - if (!oidcUser.id) { - throw new Error("Could not find sub or user_id in userinfo response"); - } - - profile.emails = oidcUser.email ? [{ value: oidcUser.email }] : []; - profile.thumbnailPhoto = this.getUserPhoto(oidcUser.thumbnailPhoto); - profile.oidcClaims = userinfo; - - const oidcUserProfile = { ...oidcUser, ...profile }; - - return oidcUserProfile; - } - - parseQueryFilter(userProfile: OidcProfile) { - const userQuery = - this.configService.get("oidc.userQuery"); - const allowedOperators = ["and", "or"]; - const defaultFilter = - userQuery && allowedOperators.includes(userQuery.operator) - ? { - [`$${userQuery.operator}`]: [ - { username: userProfile.username }, - { email: userProfile.email }, - ], - } - : { - $or: [ - { username: userProfile.username }, - { email: userProfile.email }, - ], - }; - - if ( - !userQuery?.operator || - (userQuery?.filter && userQuery.filter.length < 1) - ) { - return defaultFilter; - } - const operator = "$" + userQuery.operator.toLowerCase(); - const filter = userQuery.filter.reduce( - (acc: Record[], mapping: string) => { - const [filterField, userProfileField] = mapping.split(":"); - if (userProfileField in userProfile && UserSchema.path(filterField)) { - acc.push({ - [filterField]: userProfile[userProfileField as keyof UserProfile], - }); - } - return acc; - }, - [], - ); - - if (filter.length === 0 || !allowedOperators.includes(userQuery.operator)) { - Logger.log( - `Executing default userQuery filter: $${JSON.stringify(defaultFilter)}`, - "OidcStrategy", - ); - return defaultFilter; - } - - const customFilter = { [operator]: filter }; - Logger.log(userQuery, "Executing custom userQuery filter", "OidcStrategy"); - return customFilter; + return this.oidcAuthService.validate(tokenset); } } diff --git a/src/casl/action.enum.ts b/src/casl/action.enum.ts index 3b17d3132..baed10fe5 100644 --- a/src/casl/action.enum.ts +++ b/src/casl/action.enum.ts @@ -266,4 +266,20 @@ export enum Action { HistoryReadPolicy = "history_read_policy", HistoryReadDatablock = "history_read_datablock", HistoryReadAttachment = "history_read_attachment", + + // ------------------------------------- + // MetadataKeys + // ------------------------------------- + // metadatakeys endpoint authorization + MetadataKeysReadEndpoint = "metadatakeys_read_endpoint", + // ------------------------------------- + // metadatakeys data instance authorization + MetadataKeysReadInstance = "metadatakeys_read_instance", + + // ------------------------------------- + // RuntimeConfig + // ------------------------------------- + // runtimeconfig endpoint authorization + RuntimeConfigReadEndpoint = "runtimeconfig_read_endpoint", + RuntimeConfigUpdateEndpoint = "runtimeconfig_update_endpoint", } diff --git a/src/casl/casl-ability.factory.ts b/src/casl/casl-ability.factory.ts index ed6b95789..b95cfd510 100644 --- a/src/casl/casl-ability.factory.ts +++ b/src/casl/casl-ability.factory.ts @@ -15,7 +15,6 @@ import { JobConfig } from "src/config/job-config/jobconfig.interface"; import { JobConfigService } from "src/config/job-config/jobconfig.service"; import { Datablock } from "src/datablocks/schemas/datablock.schema"; import { DatasetClass } from "src/datasets/schemas/dataset.schema"; -import { ElasticSearchActions } from "src/elastic-search/dto"; import { Instrument } from "src/instruments/schemas/instrument.schema"; import { JobClass } from "src/jobs/schemas/job.schema"; import { CreateJobAuth, UpdateJobAuth } from "src/jobs/types/jobs-auth.enum"; @@ -31,6 +30,8 @@ import { User } from "src/users/schemas/user.schema"; import { Action } from "./action.enum"; import { RuntimeConfig } from "src/config/runtime-config/schemas/runtime-config.schema"; import { accessibleBy } from "@casl/mongoose"; +import { MetadataKeyClass } from "src/metadata-keys/schemas/metadatakey.schema"; +import { Opensearch } from "src/opensearch/opensearch.subject"; type Subjects = | string @@ -49,9 +50,10 @@ type Subjects = | typeof User | typeof UserIdentity | typeof UserSettings - | typeof ElasticSearchActions + | typeof Opensearch | typeof Datablock | typeof RuntimeConfig + | typeof MetadataKeyClass > | "all"; type PossibleAbilities = [Action, Subjects]; @@ -74,7 +76,7 @@ export class CaslAbilityFactory { [endpoint: string]: (user: JWTUser) => AppAbility; } = { datasets: this.datasetEndpointAccess, - "elastic-search": this.elasticSearchEndpointAccess, + opensearch: this.opensearchEndpointAccess, jobs: this.jobsEndpointAccess, instruments: this.instrumentEndpointAccess, logbooks: this.logbookEndpointAccess, @@ -88,6 +90,7 @@ export class CaslAbilityFactory { history: this.historyEndpointAccess, datablocks: this.datablockEndpointAccess, runtimeconfig: this.runtimeConfigEndpointAccess, + metadataKeys: this.metadataKeysEndpointAccess, }; endpointAccess(endpoint: string, user: JWTUser) { @@ -325,7 +328,7 @@ export class CaslAbilityFactory { }); } - elasticSearchEndpointAccess(user: JWTUser) { + opensearchEndpointAccess(user: JWTUser) { const { can, build } = new AbilityBuilder( createMongoAbility, ); @@ -337,7 +340,7 @@ export class CaslAbilityFactory { /* / user that belongs to any of the group listed in ADMIN_GROUPS */ - can(Action.Manage, ElasticSearchActions); + can(Action.Manage, Opensearch); } return build({ detectSubjectType: (item) => @@ -919,7 +922,7 @@ export class CaslAbilityFactory { createMongoAbility, ); - can(Action.Read, RuntimeConfig); + can(Action.RuntimeConfigReadEndpoint, RuntimeConfig); if ( user && user.currentGroups.some((g) => this.accessGroups?.admin.includes(g)) @@ -927,7 +930,7 @@ export class CaslAbilityFactory { /* / user that belongs to any of the group listed in ADMIN_GROUPS */ - can(Action.Update, RuntimeConfig); + can(Action.RuntimeConfigUpdateEndpoint, RuntimeConfig); } return build({ detectSubjectType: (item) => @@ -935,6 +938,20 @@ export class CaslAbilityFactory { }); } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + metadataKeysEndpointAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + + can(Action.MetadataKeysReadEndpoint, MetadataKeyClass); + + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + policyEndpointAccess(user: JWTUser) { const { can, build } = new AbilityBuilder( createMongoAbility, @@ -2374,4 +2391,40 @@ export class CaslAbilityFactory { item.constructor as ExtractSubjectType, }); } + + metadataKeyInstanceAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + // ------------------------------------- + // any user can read public attachments + // ------------------------------------- + can(Action.MetadataKeysReadInstance, MetadataKeyClass, { + isPublished: true, + }); + if (user) { + if ( + user.currentGroups.some((g) => this.accessGroups?.admin.includes(g)) + ) { + // ------------------------------------- + // users belonging to any of the group listed in ADMIN_GROUPS + // ------------------------------------- + + can(Action.MetadataKeysReadInstance, MetadataKeyClass); + } else { + // ------------------------------------- + // users with no elevated permissions + // ------------------------------------- + + can(Action.MetadataKeysReadInstance, MetadataKeyClass, { + userGroups: { $in: user.currentGroups }, + }); + } + } + + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } } diff --git a/src/auth/interfaces/oidc-user.interface.ts b/src/common/openid-client/interfaces/oidc-user.interface.ts similarity index 100% rename from src/auth/interfaces/oidc-user.interface.ts rename to src/common/openid-client/interfaces/oidc-user.interface.ts diff --git a/src/common/openid-client/openid-auth.service.ts b/src/common/openid-client/openid-auth.service.ts new file mode 100644 index 000000000..202c029d9 --- /dev/null +++ b/src/common/openid-client/openid-auth.service.ts @@ -0,0 +1,221 @@ +import { + Injectable, + InternalServerErrorException, + Logger, +} from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { IdTokenClaims, TokenSet, UserinfoResponse } from "openid-client"; +import { Profile } from "passport"; +import { OidcConfig } from "src/config/configuration"; +import { UserProfile } from "src/users/schemas/user-profile.schema"; +import { User, UserDocument, UserSchema } from "src/users/schemas/user.schema"; +import { + IOidcUserInfoMapping, + IOidcUserQueryMapping, +} from "./interfaces/oidc-user.interface"; +import { AccessGroupService } from "src/auth/access-group-provider/access-group.service"; +import { UsersService } from "src/users/users.service"; +import { FilterQuery } from "mongoose"; +import { UserPayload } from "src/auth/interfaces/userPayload.interface"; +import { CreateUserIdentityDto } from "src/users/dto/create-user-identity.dto"; +import { CreateUserDto } from "src/users/dto/create-user.dto"; + +export type extendedIdTokenClaims = IdTokenClaims & + UserinfoResponse & { + groups?: string[]; + }; +export type OidcProfile = Profile & UserProfile; + +@Injectable() +export class OidcAuthService { + constructor( + private configService: ConfigService, + private accessGroupService: AccessGroupService, + private usersService: UsersService, + ) {} + + async validate(tokenset: TokenSet): Promise> { + const userinfo: extendedIdTokenClaims = tokenset.claims(); + + const oidcConfig = this.configService.get("oidc"); + + const userProfile = this.parseUserInfo(userinfo); + + const userPayload: UserPayload = { + userId: userProfile.id, + username: userProfile.username, + email: userProfile.email, + accessGroupProperty: oidcConfig?.accessGroupProperty, + payload: userinfo, + }; + userProfile.accessGroups = + await this.accessGroupService.getAccessGroups(userPayload); + + const userFilter: FilterQuery = + this.parseQueryFilter(userProfile); + + let user = await this.usersService.findOne(userFilter); + + if (!user) { + const createUser: CreateUserDto = { + username: userProfile.username, + email: userProfile.email as string, + authStrategy: "oidc", + }; + + const newUser = await this.usersService.create(createUser); + if (!newUser) { + throw new InternalServerErrorException( + "Could not create User from OIDC response.", + ); + } + Logger.log("Created oidc user ", newUser.username); + + const createUserIdentity: CreateUserIdentityDto = { + authStrategy: "oidc", + credentials: {}, + externalId: userProfile.id, + profile: userProfile, + provider: userProfile.provider || "oidc", + userId: newUser._id, + }; + + await this.usersService.createUserIdentity(createUserIdentity); + Logger.log("Created user identity for oidc user with id ", newUser._id); + + user = newUser; + } else { + await this.usersService.updateUser( + { username: userProfile.username }, + user._id, + ); + await this.usersService.updateUserIdentity( + { + profile: userProfile, + externalId: userProfile.id, + provider: userProfile.provider || "oidc", + }, + user._id, + ); + } + + const jsonUser = JSON.parse(JSON.stringify(user)); + const { ...returnUser } = jsonUser; + returnUser.userId = returnUser._id; + + return returnUser; + } + + getUserPhoto(thumbnailPhoto: string) { + return thumbnailPhoto + ? "data:image/jpeg;base64," + + Buffer.from(thumbnailPhoto, "binary").toString("base64") + : "no photo"; + } + + parseUserInfo(userinfo: extendedIdTokenClaims) { + const profile = {} as OidcProfile; + + const customUserInfoFields = this.configService.get( + "oidc.userInfoMapping", + ); + + // To dynamically map user info fields based on environment variables, + // set mappings like OIDC_USERINFO_MAPPING_FIELD_USERNAME=family_name. + // This assigns userinfo.family_name to oidcUser.username. + + const oidcUser: IOidcUserInfoMapping = { + id: userinfo["sub"] ?? (userinfo["user_id"] as string) ?? "", + username: userinfo["preferred_username"] ?? userinfo["name"] ?? "", + displayName: userinfo["name"] ?? "", + familyName: userinfo["family_name"] ?? "", + email: userinfo["email"] ?? "", + thumbnailPhoto: (userinfo["thumbnailPhoto"] as string) ?? "", + provider: userinfo["iss"] ?? "", + groups: userinfo["groups"] ?? [], + }; + + if (customUserInfoFields) { + Object.entries(customUserInfoFields).forEach( + ([sourceField, targetField]) => { + if (typeof targetField === "string" && targetField in userinfo) { + oidcUser[sourceField] = userinfo[targetField] as string; + } else if (Array.isArray(targetField) && targetField.length) { + const values = targetField + .filter((field) => field in userinfo) + .map((field) => userinfo[field] as string); + + if (values.length) { + oidcUser[sourceField] = values.join("_"); + } + } + }, + ); + } + + // Prior to OpenID Connect Basic Client Profile 1.0 - draft 22, the "sub" + // claim was named "user_id". Many providers still use the old name, so + // fallback to that. https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + + if (!oidcUser.id) { + throw new Error("Could not find sub or user_id in userinfo response"); + } + + profile.emails = oidcUser.email ? [{ value: oidcUser.email }] : []; + profile.thumbnailPhoto = this.getUserPhoto(oidcUser.thumbnailPhoto); + profile.oidcClaims = userinfo; + + const oidcUserProfile = { ...oidcUser, ...profile }; + + return oidcUserProfile; + } + + parseQueryFilter(userProfile: OidcProfile) { + const userQuery = + this.configService.get("oidc.userQuery"); + const allowedOperators = ["and", "or"]; + const defaultFilter = + userQuery && allowedOperators.includes(userQuery.operator) + ? { + [`$${userQuery.operator}`]: [ + { username: userProfile.username }, + { email: userProfile.email }, + ], + } + : { + $or: [ + { username: userProfile.username }, + { email: userProfile.email }, + ], + }; + + if (!userQuery?.operator || !userQuery.filter.length) { + return defaultFilter; + } + const operator = "$" + userQuery.operator.toLowerCase(); + const filter = userQuery.filter.reduce( + (acc: Record[], mapping: string) => { + const [filterField, userProfileField] = mapping.split(":"); + if (userProfileField in userProfile && UserSchema.path(filterField)) { + acc.push({ + [filterField]: userProfile[userProfileField as keyof UserProfile], + }); + } + return acc; + }, + [], + ); + + if (filter.length === 0 || !allowedOperators.includes(userQuery.operator)) { + Logger.log( + `Executing default userQuery filter: $${JSON.stringify(defaultFilter)}`, + "OidcStrategy", + ); + return defaultFilter; + } + + const customFilter = { [operator]: filter }; + Logger.log(userQuery, "Executing custom userQuery filter", "OidcStrategy"); + return customFilter; + } +} diff --git a/src/common/openid-client/openid-client.module.ts b/src/common/openid-client/openid-client.module.ts new file mode 100644 index 000000000..30e2ac741 --- /dev/null +++ b/src/common/openid-client/openid-client.module.ts @@ -0,0 +1,14 @@ +import { Global } from "@nestjs/common"; +import { Module } from "@nestjs/common"; +import { OidcClientService } from "./openid-client.service"; +import { accessGroupServiceFactory } from "src/auth/access-group-provider/access-group-service-factory"; +import { UsersModule } from "src/users/users.module"; +import { OidcAuthService } from "./openid-auth.service"; + +@Global() +@Module({ + imports: [UsersModule], + providers: [OidcClientService, OidcAuthService, accessGroupServiceFactory], + exports: [OidcClientService, OidcAuthService], +}) +export class OidcClientModule {} diff --git a/src/common/openid-client/openid-client.service.ts b/src/common/openid-client/openid-client.service.ts new file mode 100644 index 000000000..ca8ddce8e --- /dev/null +++ b/src/common/openid-client/openid-client.service.ts @@ -0,0 +1,66 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { + Client, + IdTokenClaims, + Issuer, + UserinfoResponse, + custom, +} from "openid-client"; +import { Profile } from "passport"; +import { OidcConfig } from "src/config/configuration"; +import { UserProfile } from "src/users/schemas/user-profile.schema"; + +export type extendedIdTokenClaims = IdTokenClaims & + UserinfoResponse & { + groups?: string[]; + }; +export type OidcProfile = Profile & UserProfile; + +@Injectable() +export class OidcClientService { + private client: Client | null = null; + private oidcConfig?: OidcConfig; + + constructor(private configService: ConfigService) { + this.oidcConfig = this.configService.get("oidc"); + + // Set a reasonable timeout for HTTP requests made by the openid-client library + custom.setHttpOptionsDefaults({ + timeout: 7000, + }); + } + + async getClient(): Promise { + if (this.client) return this.client; + + if (!this.oidcConfig?.clientID) { + throw new Error("OIDC clientID not defined in the configuration."); + } + try { + const issuer = await Issuer.discover( + `${this.oidcConfig.issuer}/.well-known/openid-configuration`, + ); + + this.client = new issuer.Client( + { + client_id: this.oidcConfig.clientID, + client_secret: this.oidcConfig.clientSecret, + }, + undefined, // use issuer's JWKS + this.oidcConfig.additionalAuthorizedParties?.length + ? { + additionalAuthorizedParties: + this.oidcConfig.additionalAuthorizedParties, + } + : undefined, + ); + + return this.client; + } catch (err) { + throw new Error( + `OIDC issuer discovery failed: ${err instanceof Error ? err.message : err}`, + ); + } + } +} diff --git a/src/common/pipes/filter.pipe.ts b/src/common/pipes/filter.pipe.ts index 253d41beb..004bdc5de 100644 --- a/src/common/pipes/filter.pipe.ts +++ b/src/common/pipes/filter.pipe.ts @@ -153,7 +153,8 @@ export class WherePipe extends FilterPipeAbstract { }, }, valueFn: (val: unknown) => { - if (typeof val !== "string") return val; + if (typeof val !== "string" || !/^\d{4}-\d{2}-\d{2}/.test(val)) + return val; const dateFromString = new Date(val); return isNaN(dateFromString.getTime()) ? val : dateFromString; }, diff --git a/src/common/schemas/ownable.schema.ts b/src/common/schemas/ownable.schema.ts index c0e6f686b..137c9b5f0 100644 --- a/src/common/schemas/ownable.schema.ts +++ b/src/common/schemas/ownable.schema.ts @@ -22,6 +22,7 @@ export class OwnableClass extends QueryableClass { @Prop({ type: [String], index: true, + default: [], }) accessGroups: string[] = []; diff --git a/src/common/types.ts b/src/common/types.ts index f2c4ea9d0..a716b66d6 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,6 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { ValidationError } from "class-validator"; -import { IFullFacets } from "src/elastic-search/interfaces/es-common.type"; export class FullFacetFilters { @ApiPropertyOptional() @@ -23,7 +22,7 @@ class TotalSets { totalSets: number; } -export class FullFacetResponse implements IFullFacets { +export class FullFacetResponse { @ApiProperty({ type: TotalSets, isArray: true }) all: [TotalSets]; diff --git a/src/common/utils.ts b/src/common/utils.ts index fc1e48234..9d118df66 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -700,6 +700,17 @@ export const createFullqueryFilter = ( }; const pipelineHandler = { + handleOpensearchIdList: ( + pipeline: PipelineStage[], + fields: Y, + key: string, + ) => { + const match = { + $match: { _id: { $in: fields[key as keyof Y] as string[] } }, + }; + return pipeline.unshift(match); + }, + handleTextSearch: ( pipeline: PipelineStage[], model: Model, @@ -836,11 +847,14 @@ export const createFullfacetPipeline = ( } switch (key) { + case "openSearchIdList": + pipelineHandler.handleOpensearchIdList(pipeline, fields, key); + break; case "text": - pipelineHandler.handleTextSearch(pipeline, model, fields, key); + pipelineHandler.handleTextSearch(pipeline, model, fields, key); break; case idField: - pipelineHandler.handleIdFieldSearch( + pipelineHandler.handleIdFieldSearch( pipeline, model, fields, @@ -849,17 +863,22 @@ export const createFullfacetPipeline = ( ); break; case "mode": - pipelineHandler.handleModeSearch(pipeline, fields, key, idField); + pipelineHandler.handleModeSearch(pipeline, fields, key, idField); break; case "userGroups": - pipelineHandler.handleUserGroupSearch(pipeline, model, fields, key); + pipelineHandler.handleUserGroupSearch( + pipeline, + model, + fields, + key, + ); break; case "scientific": case "sampleCharacteristics": - pipelineHandler.handleScientificQuery(pipeline, fields, key); + pipelineHandler.handleScientificQuery(pipeline, fields, key); break; default: - pipelineHandler.handleGenericSearch(pipeline, model, fields, key); + pipelineHandler.handleGenericSearch(pipeline, model, fields, key); } }); diff --git a/src/common/utils/check-unmodified-since.ts b/src/common/utils/check-unmodified-since.ts index 70dab4743..bed35ad84 100644 --- a/src/common/utils/check-unmodified-since.ts +++ b/src/common/utils/check-unmodified-since.ts @@ -21,7 +21,7 @@ export function checkUnmodifiedSince( const headerDate = new Date(headerDateString); if (isNaN(headerDate.getTime())) return; - if (headerDate <= resourceDate) { + if (headerDate < resourceDate) { throw new PreconditionFailedException( "Resource has been modified on server", ); diff --git a/src/common/utils/deep-mapper.util.ts b/src/common/utils/deep-mapper.util.ts index 7c685b6fe..9c36ae381 100644 --- a/src/common/utils/deep-mapper.util.ts +++ b/src/common/utils/deep-mapper.util.ts @@ -1,26 +1,27 @@ -import { get } from "lodash"; +import { get, trim } from "lodash"; function mapDeep( source: T, - key: keyof U | string, - fieldsMap: Record, + key: keyof U & string, + fieldsMap: Partial>, ): T[keyof T] | unknown | null { if (!source) return null; + if (!fieldsMap[key]) return get(source, key); if (get(source, key)) return get(source, key); - const keysList = (fieldsMap[key] as string).split("."); - const initialValue = get(source, keysList[0]); + if (!fieldsMap[key].includes("[]")) return get(source, fieldsMap[key]); + const keysList = fieldsMap[key].split("[]"); + const initialValue = get(source, trim(keysList[0], ".")); + if (!initialValue) return; return keysList.slice(1).reduce((acc, currKey) => { - if (Array.isArray(acc)) { - return acc.map((item) => get(item, currKey)); - } - return get(acc, currKey); + if (!acc) return acc; + return acc.map((item: object) => get(item, trim(currKey, "."))); }, initialValue); } export function createDeepMapper( - fieldsMap: Record, + fieldsMap: Partial>, ) { - return (source: T, key: keyof U | string) => { - return mapDeep(source, key, fieldsMap); + return (source: T, key: string) => { + return mapDeep(source, key as keyof U & string, fieldsMap); }; } diff --git a/src/config/configuration.ts b/src/config/configuration.ts index 1115bfbc1..757736c68 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -1,9 +1,9 @@ import * as fs from "fs"; import { merge } from "lodash"; -import localconfiguration from "./localconfiguration"; import { boolean } from "mathjs"; -import { DEFAULT_PROPOSAL_TYPE } from "src/proposals/schemas/proposal.schema"; import { DatasetType } from "src/datasets/types/dataset-type.enum"; +import { DEFAULT_PROPOSAL_TYPE } from "src/proposals/schemas/proposal.schema"; +import localconfiguration from "./localconfiguration"; const configuration = () => { const accessGroupsStaticValues = @@ -64,6 +64,8 @@ const configuration = () => { const jobConfigurationFile = process.env.JOB_CONFIGURATION_FILE || ""; + const ajvCustomDefinitions = process.env.AJV_CUSTOM_DEFINITIONS_FILE || ""; + const defaultLogger = { type: "DefaultLogger", modulePath: "./loggingProviders/defaultLogger", @@ -72,6 +74,7 @@ const configuration = () => { const jsonConfigMap: { [key: string]: object | object[] | boolean } = { datasetTypes: {}, proposalTypes: {}, + opensearchConfig: {}, }; const jsonConfigFileList: { [key: string]: string } = { frontendConfig: @@ -84,6 +87,8 @@ const configuration = () => { metricsConfig: process.env.METRICS_CONFIG_FILE || "metricsConfig.json", publishedDataConfig: process.env.PUBLISHED_DATA_CONFIG_FILE || "publishedDataConfig.json", + opensearchConfig: + process.env.OPENSEARCH_CONFIG_FILE || "opensearchConfig.json", }; Object.keys(jsonConfigFileList).forEach((key) => { const filePath = jsonConfigFileList[key]; @@ -98,7 +103,11 @@ const configuration = () => { jsonConfigMap[key] = false; } } else { - if (key === "publishedDataConfig") { + const configsWithExampleFallback = [ + "publishedDataConfig", + "opensearchConfig", + ]; + if (configsWithExampleFallback.includes(key)) { console.warn( `Configuration file ${filePath} does not exist. Trying to use the example ${key}.example.json file`, ); @@ -289,6 +298,14 @@ const configuration = () => { enabled: boolean(process.env?.ACCESS_GROUPS_OIDCPAYLOAD_ENABLED || false), accessGroupProperty: process.env?.OIDC_ACCESS_GROUPS_PROPERTY, // Example: groups }, + accessGroupsRestConfig: { + enabled: boolean(process.env?.ACCESS_GROUPS_REST_ENABLED || false), + authKey: + process.env?.ACCESS_GROUPS_SERVICE_REST_AUTH_KEY || "Authorization", + token: process.env.ACCESS_GROUPS_SERVICE_REST_AUTH_VALUE, + apiUrl: process.env.ACCESS_GROUPS_SERVICE_REST_API_URL, + userIdField: process.env.ACCESS_GROUPS_SERVICE_REST_USER_ID_FIELD, + }, doiPrefix: process.env.DOI_PREFIX, expressSession: { secret: process.env.EXPRESS_SESSION_SECRET, @@ -344,6 +361,12 @@ const configuration = () => { operator: process.env.OIDC_USERQUERY_OPERATOR || "or", // Example: "or" or "and" filter: oidcUserQueryFilter.split(",").map((v) => v.trim()) ?? [], // Example: "username:username, email:email" }, + additionalAuthorizedParties: process.env + .OIDC_ADDITIONAL_AUTHORIZED_PARTIES + ? process.env.OIDC_ADDITIONAL_AUTHORIZED_PARTIES.split(",") + .map((v) => v.trim()) + .filter(Boolean) + : undefined, // Example: "public-client-id" or "client1,client2" }, logbook: { enabled: @@ -372,16 +395,17 @@ const configuration = () => { username: process.env.RABBITMQ_USERNAME, password: process.env.RABBITMQ_PASSWORD, }, - elasticSearch: { - enabled: process.env.ELASTICSEARCH_ENABLED ?? "no", - username: process.env.ES_USERNAME, - password: process.env.ES_PASSWORD, - host: process.env.ES_HOST, - refresh: process.env.ES_REFRESH, - maxResultWindow: parseInt(process.env.ES_MAX_RESULT || "100000", 10), - fieldsLimit: parseInt(process.env.ES_FIELDS_LIMIT || "100000", 10), - mongoDBCollection: process.env.MONGODB_COLLECTION, - defaultIndex: process.env.ES_INDEX ?? "dataset", + opensearch: { + enabled: process.env.OPENSEARCH_ENABLED ?? "no", + username: process.env.OPENSEARCH_USERNAME ?? "admin", + password: process.env.OPENSEARCH_PASSWORD, + host: process.env.OPENSEARCH_HOST, + refresh: process.env.OPENSEARCH_REFRESH, + defaultIndex: process.env.OPENSEARCH_DEFAULT_INDEX ?? "dataset", + dataSyncBatchSize: parseInt( + process.env.OPENSEARCH_DATA_SYNC_BATCH_SIZE || "1000", + 10, + ), }, metrics: { // Note: `process.env.METRICS_ENABLED` is directly used for conditional module loading in @@ -420,6 +444,8 @@ const configuration = () => { frontendConfig: jsonConfigMap.frontendConfig, frontendTheme: jsonConfigMap.frontendTheme, publishedDataConfig: jsonConfigMap.publishedDataConfig, + ajvCustomDefinitions: ajvCustomDefinitions, + opensearchConfig: jsonConfigMap.opensearchConfig, }; return merge(config, localconfiguration); }; diff --git a/src/config/frontend.config.json b/src/config/frontend.config.json index 6f6669638..56e67de1e 100644 --- a/src/config/frontend.config.json +++ b/src/config/frontend.config.json @@ -3,19 +3,24 @@ "nonAuthenticatedUser": "DATASETS", "authenticatedUser": "PROPOSALS" }, + "statusBannerMessage": "", + "statusBannerCode": "INFO", "checkBoxFilterClickTrigger": false, "accessTokenPrefix": "Bearer ", "addDatasetEnabled": false, + "allowConfigOverrides": true, "archiveWorkflowEnabled": false, "datasetReduceEnabled": true, "datasetJsonScientificMetadata": true, "editDatasetEnabled": true, "editDatasetSampleEnabled": true, "editMetadataEnabled": true, + "editPublishedData": true, "addSampleEnabled": false, "externalAuthEndpoint": "/api/v3/auth/msad", "facility": "SciCat Vanilla", "siteIcon": "site-header-logo.png", + "siteHeaderLogoUrl": "https://my.facility.site", "siteTitle": "Local development", "siteSciCatLogo": "full", "loginFacilityLabel": "SciCat Vanilla", @@ -33,8 +38,19 @@ "jupyterHubUrl": "", "landingPage": "doi.ess.eu/detail/", "lbBaseURL": "http://localhost:3000", - "logbookEnabled": true, + "ingestorComponent": { + "ingestorEnabled": false, + "ingestorAutodiscoveryOptions": [ + { + "mailDomain": "university.ch", + "description": "University/facility of Choice", + "facilityBackend": "http://localhost:8888" + } + ] + }, + "logbookEnabled": false, "loginFormEnabled": true, + "thumbnailFetchLimitPerPage": 100, "metadataPreviewEnabled": true, "metadataStructure": "", "multipleDownloadAction": "http:/127.0.0.1:3012/zip", @@ -53,10 +69,10 @@ "searchPublicDataEnabled": true, "searchSamples": true, "sftpHost": "login.esss.dk", + "shareEnabled": false, "sourceFolder": "/data/ess", "maxDirectDownloadSize": 5000000000, "maxFileSizeWarning": "Some files are above and cannot be downloaded directly. These file can be downloaded via sftp host: in directory: ", - "shareEnabled": true, "shoppingCartEnabled": true, "shoppingCartOnHeader": true, "tableSciDataEnabled": true, @@ -69,135 +85,429 @@ { "id": "eed8efec-4354-11ef-a3b5-d75573a5d37f", "description": "This action let users download all files using the zip service", - "order": 4, + "order": 1, "label": "Download All", "files": "all", "mat_icon": "download", + "type": "form", "url": "https://zip.scicatproject.org/download/all", "target": "_blank", - "enabled": "#SizeLimit", + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0FilesPath", + "totalSize": "#Dataset0FilesTotalSize", + "folder": "#Dataset0SourceFolder" + }, + "enabled": "#MaxDownloadableSize(@totalSize)", + "inputs": { + "item[]": "@pid", + "directory[]": "@folder", + "files[]": "@files" + }, "authorization": ["#datasetAccess", "#datasetPublic"] }, { "id": "3072fafc-4363-11ef-b9f9-ebf568222d26", "description": "This action let users download selected files using the zip service", - "order": 3, + "order": 2, "label": "Download Selected", "files": "selected", "mat_icon": "download", + "type": "form", "url": "https://zip.scicatproject.org/download/selected", "target": "_blank", - "enabled": "#Selected && #SizeLimit", + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0SelectedFilesPath", + "selected": "#Dataset0SelectedFilesCount", + "totalSize": "#Dataset0SelectedFilesTotalSize", + "folder": "#Dataset0SourceFolder" + }, + "inputs": { + "auth_token": "#tokenBearer", + "jwt": "#jwt", + "item[]": "@pid", + "directory[]": "@folder", + "files[]": "@files" + }, + "enabled": "#Length(@files) && #MaxDownloadableSize(@totalSize)", "authorization": ["#datasetAccess", "#datasetPublic"] }, { "id": "4f974f0e-4364-11ef-9c63-03d19f813f4e", "description": "This action let users download jupyter notebook properly populated with dataset pid and all files using an instance of sciwyrm", - "order": 2, - "label": "Notebook All", + "order": 3, + "label": "Notebook All (Form)", + "files": "all", + "icon": "/assets/icons/jupyter_logo.png", + "type": "form", + "url": "https://www.scicat.info/notebook/all", + "target": "_blank", + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0FilesPath", + "totalSize": "#Dataset0FilesTotalSize", + "folder": "#Dataset0SourceFolder" + }, + "enabled": "", + "inputs": { + "auth_token": "#token", + "jwt": "#jwt", + "item[]": "@pid", + "directory[]": "@folder", + "files[]": "@files" + }, + "authorization": ["#datasetAccess", "#datasetPublic"] + }, + { + "id": "fa3ce6ee-482d-11ef-95e9-ff2c80dd50bd", + "order": 4, + "label": "Notebook Selected (Form)", + "files": "selected", + "icon": "/assets/icons/jupyter_logo.png", + "type": "form", + "url": "https://www.scicat.info/notebook/selected", + "target": "_blank", + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0SelectedFilesPath", + "selected": "#Dataset0SelectedFilesCount", + "totalSize": "#Dataset0SelectedFilesTotalSize", + "folder": "#Dataset0SourceFolder" + }, + "inputs": { + "auth_token": "#token", + "jwt": "#jwt", + "item[]": "@pid", + "directory[]": "@folder", + "files[]": "@files" + }, + "enabled": "#Length(@files) > 0", + "authorization": ["#datasetAccess", "#datasetPublic"] + }, + { + "id": "0cd5b592-0b1a-11f0-a42c-23e177127ee7", + "description": "This action let users download jupyter notebook properly populated with dataset pid and all files using an instance of sciwyrm", + "order": 5, + "label": "Notebook All (Download JSON)", "files": "all", "type": "json-download", "icon": "/assets/icons/jupyter_logo.png", - "url": "https://sciiwyrm.scicatproject.org/notebook", + "url": "https://www.sciwyrm.info/notebook", "target": "_blank", "authorization": ["#datasetAccess", "#datasetPublic"], - "payload": "{\"template_id\":\"c975455e-ede3-11ef-94fb-138c9cd51fc0\",\"parameters\":{\"dataset\":\"{{ datasetPid }}\",\"directory\":\"{{ sourceFolder }}\",\"files\": {{ filesPath }},\"jwt\":\"{{ jwt }}\",\"scicat_url\":\"https://staging.scicat.ess.url\",\"file_server_url\":\"sftserver2.esss.dk\",\"file_server_port\":\"22\"}}", - "filename": "{{ uuid }}.ipynb" + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0FilesPath", + "folder": "#Dataset0SourceFolder" + }, + "payload": "{\"template_id\":\"c975455e-ede3-11ef-94fb-138c9cd51fc0\",\"parameters\":{\"dataset\":\"{{ @pid }}\",\"directory\":\"{{ @folder }}\",\"files\": {{ @files[] }},\"jwt\":\"{{ #jwt }}\",\"scicat_url\":\"https://staging.scicat.ess.url\",\"file_server_url\":\"sftserver2.esss.dk\",\"file_server_port\":\"22\"}}", + "filename": "{{ #uuid }}.ipynb" }, { - "id": "fa3ce6ee-482d-11ef-95e9-ff2c80dd50bd", + "id": "a414773a-a526-11f0-a7f2-ff1026e5dba9", "description": "This action let users download jupyter notebook properly populated with dataset pid and selected files using an instance of sciwyrm", - "order": 1, - "label": "Notebook Selected", - "files": "selected", + "order": 6, + "label": "Notebook Selected (Download JSON)", "type": "json-download", "icon": "/assets/icons/jupyter_logo.png", - "url": "https://sciwyrm.scicatproject.org/notebook", + "url": "https://www.sciwyrm.info/notebook", "target": "_blank", - "enabled": "#Selected", + "enabled": "#Length(@files) > 0", "authorization": ["#datasetAccess", "#datasetPublic"], - "payload": "{\"template_id\":\"c975455e-ede3-11ef-94fb-138c9cd51fc0\",\"parameters\":{\"dataset\":\"{{ datasetPid }}\",\"directory\":\"{{ sourceFolder }}\",\"files\": {{ filesPath }},\"jwt\":\"{{ jwt }}\",\"scicat_url\":\"https://staging.scicat.ess.url\",\"file_server_url\":\"sftserver2.esss.dk\",\"file_server_port\":\"22\"}}", - "filename": "{{ uuid }}.ipynb" + "variables": { + "pid": "#Dataset0Pid", + "files": "#Dataset0SelectedFilesPath", + "selected": "#Dataset0SelectedFiles", + "folder": "#Dataset0SourceFolder" + }, + "payload": "{\"template_id\":\"c975455e-ede3-11ef-94fb-138c9cd51fc0\",\"parameters\":{\"dataset\":\"{{ @pid }}\",\"directory\":\"{{ @folder }}\",\"files\": {{ @files[] }},\"jwt\":\"{{ #jwt }}\",\"scicat_url\":\"https://staging.scicat.ess.url\",\"file_server_url\":\"sftserver2.esss.dk\",\"file_server_port\":\"22\"}}", + "filename": "{{ #uuid }}.ipynb" + }, + { + "id": "9c6a11b6-a526-11f0-8795-6f025b320cc3", + "description": "This action let users make a call an arbitrary URL and store the reply in the store", + "order": 7, + "label": "Publish", + "type": "xhr", + "mat_icon": "lock_open", + "method": "PATCH", + "url": "http://localhost:3000/dataset/{{ @pid }}/", + "target": "_blank", + "enabled": "(#datasetOwner || #userIsAdmin) && !@isPublished", + "authorization": "#datasetOwner && !@isPublished", + "variables": { + "pid": "@Dataset0Pid", + "isPublished": "#Dataset[0]Field[isPublished]" + }, + "payload": "{\"isPublished\":\"true\"}", + "headers": { + "Content-Type": "application/json", + "Authorization": "#tokenBearer" + } + }, + { + "id": "94a1d694-a526-11f0-947b-038d53cd837a", + "description": "This action let users make a call an arbitrary URL and store the reply in the store", + "order": 8, + "label": "Unpublish", + "type": "xhr", + "mat_icon": "lock", + "method": "PATCH", + "url": "http://localhost:3000/dataset/{{ @pid }}/", + "target": "_blank", + "enabled": "(#datasetOwner || #userIsAdmin) && @isPublished", + "authorization": "#datasetOwner && @isPublished", + "variables": { + "pid": "#Dataset0Pid", + "isPublished": "#Dataset[0]Field[isPublished]" + }, + "payload": "{\"isPublished\":\"false\"}", + "headers": { + "Content-Type": "application/json", + "Authorization": "#tokenBearer" + } + }, + { + "id": "c3bcbd40-a526-11f0-915a-93eeff0860ab", + "description": "This action let users jump to another URL entirely", + "order": 9, + "label": "ESS", + "type": "link", + "icon": "/assets/icons/button_ess.png", + "url": "https://ess.eu", + "target": "_blank" } ], + "datasetDetailsActionsEnabled": false, + "datasetDetailsActions": [], + "selectionActionsEnabled": true, + "selectionActions": [], + "labelMaps": { + "filters": { + "LocationFilter": "Location", + "PidFilter": "Pid", + "GroupFilter": "Group", + "TypeFilter": "Type", + "KeywordFilter": "Keyword", + "DateRangeFilter": "Start Date - End Date", + "TextFilter": "Text" + } + }, "defaultDatasetsListSettings": { "columns": [ { "name": "select", - "order": 0, "type": "standard", + "width": 120, "enabled": true }, { "name": "pid", - "order": 1, "type": "standard", + "width": 130, "enabled": true }, { "name": "datasetName", - "order": 2, "type": "standard", + "width": 250, "enabled": true }, { "name": "runNumber", - "order": 3, "type": "standard", + "width": 120, "enabled": true }, { "name": "sourceFolder", - "order": 4, "type": "standard", - "enabled": true + "width": 200, + "enabled": false + }, + { + "name": "sourceFolderHost", + "type": "standard", + "width": 200, + "enabled": false }, { "name": "size", - "order": 5, + "width": 120, "type": "standard", "enabled": true }, { - "name": "creationTime", - "order": 6, + "name": "numberOfFiles", "type": "standard", - "enabled": true + "width": 120, + "enabled": false + }, + { + "name": "creationTime", + "type": "date", + "enabled": true, + "width": 200, + "format": "yyyy-mm-dd HH:MM" + }, + { + "name": "keywords", + "type": "list", + "enabled": false, + "width": 200 + }, + { + "name": "description", + "type": "hovercontent", + "enabled": false, + "width": 150 }, { "name": "type", - "order": 7, + "width": 120, "type": "standard", - "enabled": true + "enabled": false }, { "name": "image", - "order": 8, + "width": 120, "type": "standard", "enabled": true }, { - "name": "metadata", - "order": 9, + "name": "scientificMetadata", + "type": "hovercontent", + "width": 200, + "enabled": false + }, + { + "name": "scientificMetadataSchema", "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "scientificMetadataValid", + "type": "standard", + "width": 100, + "enabled": false + }, + { + "name": "owner", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "ownerEmail", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "orcidOfOwner", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "contactEmail", + "type": "standard", + "width": 200, "enabled": false }, { "name": "proposalId", - "order": 10, "type": "standard", + "width": 200, "enabled": true }, + { + "name": "proposalIds", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "license", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "isPublished", + "type": "standard", + "width": 100, + "enabled": false + }, + { + "name": "techniques", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "comment", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "dataQualityMetrics", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "principalInvestigator", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "startTime", + "type": "date", + "width": 200, + "enabled": false, + "format": "yyyy-mm-dd HH:MM", + "sort": "desc" + }, + { + "name": "endTime", + "type": "date", + "width": 200, + "enabled": false, + "format": "yyyy-mm-dd HH:MM" + }, + { + "name": "creationLocation", + "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "sampleIds", + "type": "standard", + "width": 200, + "enabled": false + }, { "name": "ownerGroup", - "order": 11, + "width": 120, "type": "standard", "enabled": false }, { "name": "dataStatus", - "order": 12, "type": "standard", + "width": 200, + "enabled": false + }, + { + "name": "accessGroups", + "type": "standard", + "width": 200, "enabled": false } ], @@ -251,36 +561,84 @@ "columns": [ { "name": "proposalId", - "width": 180, + "width": 120, "enabled": true }, { "name": "title", - "width": 250, + "width": 210, + "enabled": true + }, + { + "name": "instrumentName", + "width": 130, "enabled": true }, { "name": "abstract", "type": "hoverContent", - "width": 150, + "width": 120, "enabled": true }, { "name": "startTime", "type": "date", "format": "yyyy-MM-dd", - "width": 200, - "enabled": true + "width": 130, + "enabled": true, + "sort": "desc" }, { - "name": "pi_lastname", + "name": "pi_lastname, pi_firstname", "enabled": true, - "width": 200 + "width": 150 }, { "name": "numberOfDatasets", - "width": 150, + "width": 120, "enabled": true + }, + { + "name": "pi_firstname", + "width": 200, + "enabled": false + }, + { + "name": "pi_email", + "width": 150, + "enabled": false + }, + { + "name": "firstname", + "width": 200, + "enabled": false + }, + { + "name": "lastname", + "width": 200, + "enabled": false + }, + { + "name": "email", + "width": 150, + "enabled": false + }, + { + "name": "endTime", + "type": "date", + "format": "yyyy-MM-dd", + "width": 200, + "enabled": false + }, + { + "name": "parentProposalId", + "width": 130, + "enabled": false + }, + { + "name": "type", + "width": 200, + "enabled": false } ], "filters": [ @@ -318,7 +676,13 @@ "metadataJsonView": "Metadata JsonView", "datasetName": "Dataset Name", "scientificMetadata.run_number.value": "Run Number", - "scientificMetadata.start_time": "Start Time" + "scientificMetadata.start_time": "Start Time", + "runNumber": "Run Number", + "size": "Size", + "image": "Image", + "proposalId": "Proposal Id", + "startTime": "Start Time", + "endTime": "End Time" }, "proposal": { "General Information": "Proposal Information", @@ -338,7 +702,14 @@ "title": "Proposal Title", "abstract": "Abstract", "pi_lastname": "PI Last Name", + "pi_firstname": "PI First Name", + "pi_email": "PI Email", + "firstname": "Proposer First Name", + "lastname": "Proposer Last Name", + "email": "Proposer Email", + "endTime": "End Date", "type": "Type", + "parentProposalId": "Parent Proposal Id", "instrumentIds": "Instrument", "numberOfDatasets": "Number of Datasets" } @@ -550,5 +921,8 @@ "publishedData": true, "samples": true } + }, + "defaultTab": { + "proposal": "details" } } diff --git a/src/config/runtime-config/runtime-config.controller.ts b/src/config/runtime-config/runtime-config.controller.ts index fb13da0af..b4fbd835b 100644 --- a/src/config/runtime-config/runtime-config.controller.ts +++ b/src/config/runtime-config/runtime-config.controller.ts @@ -56,7 +56,7 @@ export class RuntimeConfigController { @UseGuards(PoliciesGuard) @CheckPolicies("runtimeconfig", (ability: AppAbility) => - ability.can(Action.Update, RuntimeConfig), + ability.can(Action.RuntimeConfigUpdateEndpoint, RuntimeConfig), ) @Put(":id") @ApiParam({ diff --git a/src/datablocks/datablocks.controller.ts b/src/datablocks/datablocks.controller.ts index 4694eae81..a474323a6 100644 --- a/src/datablocks/datablocks.controller.ts +++ b/src/datablocks/datablocks.controller.ts @@ -234,7 +234,9 @@ export class DatablocksController { const user: JWTUser = request.user as JWTUser; const abilities = this.caslAbilityFactory.datablockInstanceAccess(user); - const instance = await this.datablocksService.findOne({ _id: id }); + const instance = await this.datablocksService.findOne({ + where: { _id: id }, + }); if (!instance) { throw new NotFoundException(); } @@ -260,7 +262,9 @@ export class DatablocksController { @Body() updateDatablockDto: PartialUpdateDatablockDto, ): Promise { try { - const instance = await this.datablocksService.findOne({ _id: id }); + const instance = await this.datablocksService.findOne({ + where: { _id: id }, + }); const user: JWTUser = request.user as JWTUser; const ability = this.caslAbilityFactory.datablockInstanceAccess(user); diff --git a/src/datasets/datasets-access.service.ts b/src/datasets/datasets-access.service.ts index 7d23c49a3..edad74296 100644 --- a/src/datasets/datasets-access.service.ts +++ b/src/datasets/datasets-access.service.ts @@ -194,7 +194,6 @@ export class DatasetsAccessService { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can(Action.DatasetReadManyOwner, DatasetClass); if (!canViewAny) { if (canViewAccess) { @@ -208,12 +207,6 @@ export class DatasetsAccessService { ], }, }); - } else if (canViewOwner) { - fieldValue.$lookup.pipeline?.unshift({ - $match: { - ownerGroup: { $in: currentUser.currentGroups }, - }, - }); } else { fieldValue.$lookup.pipeline?.unshift({ $match: { diff --git a/src/datasets/datasets.controller.ts b/src/datasets/datasets.controller.ts index 689a29ce4..3254364d0 100644 --- a/src/datasets/datasets.controller.ts +++ b/src/datasets/datasets.controller.ts @@ -168,7 +168,7 @@ export class DatasetsController { const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); - const canViewOwner = ability.can(Action.DatasetReadManyOwner, DatasetClass); + const canViewAccess = ability.can( Action.DatasetReadManyAccess, DatasetClass, @@ -205,11 +205,6 @@ export class DatasetsController { }, ]; } - } else if (canViewOwner) { - mergedFilters.where = { - ...mergedFilters.where, - ownerGroup: { $in: user.currentGroups }, - }; } else if (canViewPublic) { mergedFilters.where = { ...mergedFilters.where, @@ -617,7 +612,7 @@ export class DatasetsController { documentId: datasetId, subsystem: "Dataset", }), - currentDataset, + currentDataset.toObject(), ).reverse(); } @@ -832,7 +827,7 @@ export class DatasetsController { | CreateRawDatasetObsoleteDto | CreateDerivedDatasetObsoleteDto | CreateDatasetDto, - ): Promise<{ valid: boolean }> { + ): Promise<{ valid: boolean; error?: string }> { await this.checkPermissionsForObsoleteDatasetCreate( request, createDatasetObsoleteDto, @@ -856,12 +851,23 @@ export class DatasetsController { ); const errorsTestCustomCorrect = await validate(dtoTestCustomCorrect); - const valid = - errorsTestRawCorrect.length == 0 || - errorsTestDerivedCorrect.length == 0 || - errorsTestCustomCorrect.length == 0; - - return { valid: valid }; + const joinErrors = (errors: ValidationError[]) => + errors + .flatMap((err) => + err.constraints ? Object.values(err.constraints) : [], + ) + .join("; "); + + let targetErrors: ValidationError[]; + if (createDatasetObsoleteDto.type === "raw") + targetErrors = errorsTestRawCorrect; + else if (createDatasetObsoleteDto.type === "derived") + targetErrors = errorsTestDerivedCorrect; + else targetErrors = errorsTestCustomCorrect; + + if (targetErrors.length > 0) + return { valid: false, error: joinErrors(targetErrors) }; + return { valid: true }; } // GET /datasets @@ -963,6 +969,11 @@ export class DatasetsController { const user: JWTUser = request.user as JWTUser; const fields: IDatasetFields = JSON.parse(filters.fields ?? "{}"); + const parsedFilters: IFilters = { + fields: fields, + limits: JSON.parse(filters.limits ?? "{}"), + }; + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); @@ -971,27 +982,15 @@ export class DatasetsController { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); if (canViewAccess) { fields.userGroups = fields.userGroups ?? []; fields.userGroups.push(...user.currentGroups); - } else if (canViewOwner) { - fields.ownerGroup = fields.ownerGroup ?? []; - fields.ownerGroup.push(...user.currentGroups); } else { fields.isPublished = true; } } - const parsedFilters: IFilters = { - fields: fields, - limits: JSON.parse(filters.limits ?? "{}"), - }; - - const datasets = await this.datasetsService.fullquery(parsedFilters); + const datasets = await this.datasetsService.opensearchQuery(parsedFilters); let outputDatasets: OutputDatasetObsoleteDto[] = []; @@ -1053,17 +1052,10 @@ export class DatasetsController { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); if (canViewAccess) { fields.userGroups = fields.userGroups ?? []; fields.userGroups.push(...user.currentGroups); - } else if (canViewOwner) { - fields.ownerGroup = fields.ownerGroup ?? []; - fields.ownerGroup.push(...user.currentGroups); } else { fields.isPublished = true; } @@ -1073,7 +1065,7 @@ export class DatasetsController { fields: fields, facets: JSON.parse(filters.facets ?? "[]"), }; - return this.datasetsService.fullFacet(parsedFilters); + return this.datasetsService.opensearchFacet(parsedFilters); } // GET /datasets/metadataKeys @@ -1124,31 +1116,14 @@ export class DatasetsController { const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); if (!canViewAny && !fields.isPublished) { - // delete fields.isPublished; - const canViewAccess = ability.can( Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); - // const canViewPublic = ability.can( - // Action.DatasetReadManyPublic, - // DatasetClass, - // ); if (canViewAccess) { fields.userGroups?.push(...user.currentGroups); - // fields.sharedWith = user.email; - // fields.isPublished = true; //are they in or? - } else if (canViewOwner) { - fields.ownerGroup?.push(...user.currentGroups); } - // else if (canViewPublic) { - // fields.isPublished = true; - // } } const parsedFilters: IFilters = { @@ -2610,7 +2585,7 @@ export class DatasetsController { if (!dataset) throw new NotFoundException(`dataset: ${pid} not found`); const datablockBeforeUpdate = await this.datablocksService.findOne({ - _id: did, + where: { _id: did }, }); if (!datablockBeforeUpdate) throw new NotFoundException(`datablock: ${did} not found`); diff --git a/src/datasets/datasets.module.ts b/src/datasets/datasets.module.ts index c1c6df8d7..0dbf18028 100644 --- a/src/datasets/datasets.module.ts +++ b/src/datasets/datasets.module.ts @@ -11,7 +11,6 @@ import { InitialDatasetsModule } from "src/initial-datasets/initial-datasets.mod import { LogbooksModule } from "src/logbooks/logbooks.module"; import { PoliciesService } from "src/policies/policies.service"; import { PoliciesModule } from "src/policies/policies.module"; -import { ElasticSearchModule } from "src/elastic-search/elastic-search.module"; import { DatasetsV4Controller } from "./datasets.v4.controller"; import { DatasetsPublicV4Controller } from "./datasets-public.v4.controller"; import { DatasetsAccessService } from "./datasets-access.service"; @@ -20,10 +19,12 @@ import { GenericHistory, GenericHistorySchema, } from "src/common/schemas/generic-history.schema"; -import { ConfigModule, ConfigService } from "@nestjs/config"; +import { ConditionalModule, ConfigModule, ConfigService } from "@nestjs/config"; import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; import { ProposalsModule } from "src/proposals/proposals.module"; import { HistoryModule } from "src/history/history.module"; +import { MetadataKeysModule } from "src/metadata-keys/metadatakeys.module"; +import { OpensearchModule } from "src/opensearch/opensearch.module"; @Module({ imports: [ @@ -33,7 +34,11 @@ import { HistoryModule } from "src/history/history.module"; OrigDatablocksModule, InitialDatasetsModule, HistoryModule, - ElasticSearchModule, + MetadataKeysModule, + ConditionalModule.registerWhen( + OpensearchModule, + (env: NodeJS.ProcessEnv) => env.OPENSEARCH_ENABLED === "yes", + ), ProposalsModule, forwardRef(() => LogbooksModule), MongooseModule.forFeatureAsync([ diff --git a/src/datasets/datasets.service.spec.ts b/src/datasets/datasets.service.spec.ts index f6a815354..d5cfef7ab 100644 --- a/src/datasets/datasets.service.spec.ts +++ b/src/datasets/datasets.service.spec.ts @@ -4,7 +4,6 @@ import { Test, TestingModule } from "@nestjs/testing"; import { Model } from "mongoose"; import { InitialDatasetsService } from "src/initial-datasets/initial-datasets.service"; import { LogbooksService } from "src/logbooks/logbooks.service"; -import { ElasticSearchService } from "src/elastic-search/elastic-search.service"; import { DatasetsService } from "./datasets.service"; import { DatasetClass } from "./schemas/dataset.schema"; import { CaslAbilityFactory } from "src/casl/casl-ability.factory"; @@ -13,6 +12,8 @@ import { Request } from "express"; import { CreateDatasetDto } from "./dto/create-dataset.dto"; import { plainToInstance } from "class-transformer"; import { ProposalsService } from "src/proposals/proposals.service"; +import { MetadataKeysService } from "src/metadata-keys/metadatakeys.service"; +import { OpensearchService } from "src/opensearch/opensearch.service"; class InitialDatasetsServiceMock {} @@ -20,7 +21,10 @@ class LogbooksServiceMock {} class CaslAbilityFactoryMock {} -class ElasticSearchServiceMock {} +class MetadataKeysServiceMock { + insertManyFromSource = jest.fn().mockResolvedValue([]); + replaceManyFromSource = jest.fn().mockResolvedValue(undefined); +} class ProposalsServiceMock { incrementNumberOfDatasets = jest.fn().mockResolvedValue(undefined); @@ -118,7 +122,8 @@ describe("DatasetsService", () => { useClass: InitialDatasetsServiceMock, }, { provide: LogbooksService, useClass: LogbooksServiceMock }, - { provide: ElasticSearchService, useClass: ElasticSearchServiceMock }, + { provide: OpensearchService, useValue: null }, + { provide: MetadataKeysService, useClass: MetadataKeysServiceMock }, { provide: CaslAbilityFactory, useClass: CaslAbilityFactoryMock }, { provide: ProposalsService, useClass: ProposalsServiceMock }, ], diff --git a/src/datasets/datasets.service.ts b/src/datasets/datasets.service.ts index e586fcb5f..7ca344075 100644 --- a/src/datasets/datasets.service.ts +++ b/src/datasets/datasets.service.ts @@ -2,7 +2,9 @@ import { BadRequestException, Inject, Injectable, + Logger, NotFoundException, + Optional, Scope, } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; @@ -34,7 +36,6 @@ import { parsePipelineSort, decodeMetadataKeyStrings, } from "src/common/utils"; -import { ElasticSearchService } from "src/elastic-search/elastic-search.service"; import { DatasetsAccessService } from "./datasets-access.service"; import { CreateDatasetDto } from "./dto/create-dataset.dto"; import { @@ -50,6 +51,7 @@ import { IDatasetFields, IDatasetFilters, IDatasetFiltersV4, + IDatasetOpenSearchPipeline, IDatasetRelation, IDatasetScopes, } from "./interfaces/dataset-filters.interface"; @@ -59,23 +61,55 @@ import { DatasetLookupKeysEnum, } from "./types/dataset-lookup"; import { ProposalsService } from "src/proposals/proposals.service"; +import { + MetadataKeysService, + MetadataSourceDoc, +} from "src/metadata-keys/metadatakeys.service"; +import { OpensearchService } from "src/opensearch/opensearch.service"; +import type { IndexSettings } from "@opensearch-project/opensearch/api/_types/indices._common"; +import type { TypeMapping } from "@opensearch-project/opensearch/api/_types/_common.mapping"; +import { BulkStats } from "@opensearch-project/opensearch/lib/Helpers"; +import { DatasetOpenSearchDto } from "src/opensearch/dto/dataset-opensearch.dto"; +import { plainToInstance } from "class-transformer"; +import { DATASET_OPENSEARCH_PROJECTION } from "../opensearch/utils/dataset-opensearch.utils"; @Injectable({ scope: Scope.REQUEST }) export class DatasetsService { - private ESClient: ElasticSearchService | null; + private readonly osDefaultIndex: string; + private readonly isOsEnabled: boolean; + private readonly osSyncBatchSize: number; + constructor( private configService: ConfigService, @InjectModel(DatasetClass.name) private datasetModel: Model, - private datasetsAccessService: DatasetsAccessService, - @Inject(ElasticSearchService) - private elasticSearchService: ElasticSearchService, @Inject(REQUEST) private request: Request, + + private datasetsAccessService: DatasetsAccessService, + @Optional() private opensearchService: OpensearchService, + private metadataKeysService: MetadataKeysService, private proposalService: ProposalsService, ) { - if (this.elasticSearchService.connected) { - this.ESClient = this.elasticSearchService; - } + this.osDefaultIndex = + this.configService.get("opensearch.defaultIndex") || "dataset"; + this.isOsEnabled = + this.configService.get("opensearch.enabled") === "yes" || false; + this.osSyncBatchSize = + this.configService.get("opensearch.dataSyncBatchSize") || 1000; + } + + private createMetadataKeysInstance( + doc: UpdateQuery, + ): MetadataSourceDoc { + const source: MetadataSourceDoc = { + sourceType: "dataset", + sourceId: doc.pid, + ownerGroup: doc.owner, + accessGroups: doc.accessGroups || [], + isPublished: doc.isPublished || false, + metadata: doc.scientificMetadata ?? {}, + }; + return source; } addLookupFields( @@ -164,18 +198,27 @@ export class DatasetsService { // insert created and updated fields addCreatedByFields(createDatasetDto, username), ); - if (this.ESClient && createdDataset) { - await this.ESClient.updateInsertDocument(createdDataset.toObject()); - } const savedDataset = await createdDataset.save(); + if (this.opensearchService && createdDataset) { + await this.opensearchService.updateInsertDocument( + plainToInstance(DatasetOpenSearchDto, savedDataset.toObject(), { + excludeExtraneousValues: true, + }), + ); + } + if (savedDataset.proposalIds && savedDataset.proposalIds.length > 0) { await this.proposalService.incrementNumberOfDatasets( savedDataset.proposalIds, ); } + this.metadataKeysService.insertManyFromSource( + this.createMetadataKeysInstance(savedDataset), + ); + return savedDataset; } @@ -253,8 +296,6 @@ export class DatasetsService { filter: IFilters, extraWhereClause: FilterQuery = {}, ): Promise { - let datasets; - const filterQuery: FilterQuery = createFullqueryFilter( this.datasetModel, @@ -268,28 +309,48 @@ export class DatasetsService { }; const modifiers: QueryOptions = parseLimitFilters(filter.limits); - const isFieldsEmpty = Object.keys(whereClause).length === 0; + const datasets = await this.datasetModel + .find(whereClause, null, modifiers) + .exec(); - // NOTE: if Elastic search DB is empty we should use default mongo query - const canPerformElasticSearchQueries = await this.isElasticSearchDBEmpty(); + return datasets; + } - if (!this.ESClient || isFieldsEmpty || !canPerformElasticSearchQueries) { - datasets = await this.datasetModel - .find(whereClause, null, modifiers) - .exec(); - } else { - const esResult = await this.ESClient.search( - filter.fields as IDatasetFields, - modifiers.limit, - modifiers.skip, - modifiers.sort, + async opensearchQuery( + filter: IFilters, + ): Promise { + if ( + !this.isOsEnabled || + !filter.fields?.text || + !this.opensearchService.connected() || + !(await this.opensearchService.isPopulated()) + ) { + return this.fullquery(filter); + } + + const { text, isPublished, userGroups } = filter.fields || {}; + + const mongoQuery: FilterQuery = + createFullqueryFilter( + this.datasetModel, + "pid", + filter.fields as FilterQuery, ); - datasets = await this.datasetModel - .find({ pid: { $in: esResult.data } }) - .sort(modifiers.sort) - .exec(); - } + const modifiers: QueryOptions = parseLimitFilters(filter.limits); + + delete mongoQuery.$text; + + const osResult = await this.opensearchService.search( + { text, userGroups, isPublished }, + this.osDefaultIndex, + modifiers.limit, + modifiers.skip, + ); + const datasets = await this.datasetModel + .find({ pid: { $in: osResult.data }, ...mongoQuery }) + .sort(modifiers.sort) + .exec(); return datasets; } @@ -297,34 +358,61 @@ export class DatasetsService { async fullFacet( filters: IFacets, ): Promise[]> { - let data; - const fields = filters.fields ?? {}; const facets = filters.facets ?? []; - // NOTE: if fields contains no value, we should use mongo query to optimize performance. - // however, fields always contain "mode" key, so we need to check if there's more than one key - const isFieldsEmpty = Object.keys(fields).length === 1; - - // NOTE: if Elastic search DB is empty we should use default mongo query - const canPerformElasticSearchQueries = await this.isElasticSearchDBEmpty(); + const pipeline = createFullfacetPipeline( + this.datasetModel, + "pid", + fields, + facets, + "", + ); - if (!this.ESClient || isFieldsEmpty || !canPerformElasticSearchQueries) { - const pipeline = createFullfacetPipeline( - this.datasetModel, - "pid", - fields, - facets, - "", - ); + return await this.datasetModel.aggregate(pipeline).exec(); + } - data = await this.datasetModel.aggregate(pipeline).exec(); - } else { - const facetResult = await this.ESClient.aggregate(fields); + async opensearchFacet( + filters: IFacets, + ): Promise[]> { + const osConfig = + this.configService.get<{ + settings: IndexSettings; + mappings: TypeMapping; + }>("opensearchConfig") || null; + const osMaxResultWindow = Number( + osConfig?.settings?.index?.max_result_window, + ); - data = facetResult; + if ( + !this.isOsEnabled || + !filters.fields?.text || + !this.opensearchService.connected() || + !(await this.opensearchService.isPopulated()) + ) { + return this.fullFacet(filters); } - return data; + const fields = filters.fields ?? {}; + const facets = filters.facets ?? []; + + const osResult = await this.opensearchService.search( + { + text: fields.text, + userGroups: fields.userGroups, + isPublished: fields.isPublished, + }, + this.osDefaultIndex, + osMaxResultWindow, + ); + + fields.openSearchIdList = osResult.data; + delete fields.text; + const pipeline = createFullfacetPipeline< + DatasetDocument, + IDatasetOpenSearchPipeline + >(this.datasetModel, "pid", fields, facets, ""); + + return await this.datasetModel.aggregate(pipeline).exec(); } async updateAll( @@ -364,17 +452,7 @@ export class DatasetsService { ): Promise<{ count: number }> { const whereFilter: RootFilterQuery = filter.where ?? {}; let count = 0; - if (this.ESClient && !filter.where) { - const totalDocCount = await this.datasetModel.countDocuments(); - - const { totalCount } = await this.ESClient.search( - whereFilter as IDatasetFields, - totalDocCount, - ); - count = totalCount; - } else { - count = await this.datasetModel.countDocuments(whereFilter).exec(); - } + count = await this.datasetModel.countDocuments(whereFilter).exec(); return { count }; } @@ -384,12 +462,12 @@ export class DatasetsService { async findByIdAndReplace( id: string, updateDatasetDto: UpdateDatasetDto, - ): Promise { + ): Promise { const username = (this.request.user as JWTUser).username; const existingDataset = await this.datasetModel.findOne({ pid: id }).exec(); if (!existingDataset) { - throw new NotFoundException(); + throw new NotFoundException(`Dataset #${id} not found`); } // TODO: This might need a discussion. // NOTE: _id, pid and some other fields should not be touched in any case. @@ -414,9 +492,17 @@ export class DatasetsService { throw new NotFoundException(`Dataset #${id} not found`); } - if (this.ESClient && updatedDataset) { - await this.ESClient.updateInsertDocument(updatedDataset.toObject()); + if (this.opensearchService) { + await this.opensearchService.updateInsertDocument( + plainToInstance(DatasetOpenSearchDto, updatedDataset.toObject(), { + excludeExtraneousValues: true, + }), + ); } + + await this.metadataKeysService.replaceManyFromSource( + this.createMetadataKeysInstance(updatedDataset), + ); // we were able to find the dataset and update it return updatedDataset; } @@ -451,38 +537,56 @@ export class DatasetsService { ) .exec(); - if (this.ESClient && patchedDataset) { - await this.ESClient.updateInsertDocument(patchedDataset.toObject()); + // check if we were able to find the dataset and update it + if (!patchedDataset) { + throw new NotFoundException(`Dataset #${id} not found`); } + + if (this.opensearchService) { + await this.opensearchService.updateInsertDocument( + plainToInstance(DatasetOpenSearchDto, patchedDataset.toObject(), { + excludeExtraneousValues: true, + }), + ); + } + + await this.metadataKeysService.replaceManyFromSource( + this.createMetadataKeysInstance(patchedDataset), + ); // we were able to find the dataset and update it return patchedDataset; } // DELETE dataset async findByIdAndDelete(id: string): Promise { - if (this.ESClient) { - await this.ESClient.deleteDocument(id); + const deletedDataset = await this.datasetModel + .findOneAndDelete({ + pid: id, + }) + .exec(); + + if (!deletedDataset) { + throw new NotFoundException(`Dataset #${id} not found`); + } + + if (this.opensearchService) { + await this.opensearchService.deleteDocument(id); } - const deletedDataset = await this.datasetModel.findOneAndDelete({ - pid: id, - }); if (deletedDataset?.proposalIds && deletedDataset.proposalIds.length > 0) { await this.proposalService.decrementNumberOfDatasets( deletedDataset.proposalIds, ); } + + // delete metadata keys associated with this dataset + await this.metadataKeysService.deleteMany({ + sourceId: id, + sourceType: "dataset", + }); + return deletedDataset; } - // GET datasets without _id which is used for elastic search data synchronization - async getDatasetsWithoutId(): Promise { - try { - const datasets = this.datasetModel.find({}, { _id: 0 }).lean().exec(); - return datasets; - } catch (error) { - throw new NotFoundException(error); - } - } // Get metadata keys async metadataKeys( @@ -548,9 +652,77 @@ export class DatasetsService { } } - async isElasticSearchDBEmpty() { - if (!this.ESClient) return; - const count = await this.ESClient.getCount(); - return count.count > 0; + async syncDatasetsToOpensearch(index: string) { + try { + await this.opensearchService.checkIndexExists(index); + + const bulkOperationFinalResult: BulkStats = { + total: 0, + failed: 0, + retry: 0, + successful: 0, + noop: 0, + time: 0, + bytes: 0, + aborted: false, + }; + + const cursor = this.datasetModel + .find({}, DATASET_OPENSEARCH_PROJECTION) + .lean() + .cursor({ batchSize: this.osSyncBatchSize }); + + let batch: DatasetClass[] = []; + let isCursorExhausted = false; + + while (!isCursorExhausted) { + const doc = await cursor.next(); + + if (doc) { + batch.push(doc as DatasetClass); + } else { + isCursorExhausted = true; + } + + // Condition: Is the batch full OR are we at the very end with a non-empty tail? + const isBatchReady = batch.length >= this.osSyncBatchSize; + const isFinalBatch = isCursorExhausted && batch.length > 0; + + if (!isBatchReady && !isFinalBatch) { + continue; + } + + // Single source of truth for the bulk operation + const bulk = + await this.opensearchService.performBulkOperation( + batch, + index, + ); + + // Aggregate bulk stats + bulkOperationFinalResult.total += bulk.total; + bulkOperationFinalResult.failed += bulk.failed; + bulkOperationFinalResult.retry += bulk.retry; + bulkOperationFinalResult.successful += bulk.successful; + bulkOperationFinalResult.noop += bulk.noop; + bulkOperationFinalResult.time += bulk.time; + bulkOperationFinalResult.bytes += bulk.bytes; + bulkOperationFinalResult.aborted = bulk.aborted; + + Logger.log( + `Synced ${bulkOperationFinalResult.total} datasets to OpenSearch (Final Batch: ${isFinalBatch})`, + "OpensearchSync", + ); + + batch = []; + } + + return bulkOperationFinalResult; + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + Logger.error(`Sync failed: ${errorMessage}`, "OpensearchSync"); + throw error; + } } } diff --git a/src/datasets/datasets.v4.controller.spec.ts b/src/datasets/datasets.v4.controller.spec.ts index 2e3f765de..c18e18d03 100644 --- a/src/datasets/datasets.v4.controller.spec.ts +++ b/src/datasets/datasets.v4.controller.spec.ts @@ -28,7 +28,8 @@ describe("DatasetsController", () => { ], }).compile(); - controller = module.get(DatasetsV4Controller); + controller = + await module.resolve(DatasetsV4Controller); }); it("should be defined", () => { diff --git a/src/datasets/datasets.v4.controller.ts b/src/datasets/datasets.v4.controller.ts index b0ebc9311..bf9219786 100644 --- a/src/datasets/datasets.v4.controller.ts +++ b/src/datasets/datasets.v4.controller.ts @@ -218,7 +218,6 @@ export class DatasetsV4Controller { ): IDatasetFiltersV4 { const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); - const canViewOwner = ability.can(Action.DatasetReadManyOwner, DatasetClass); const canViewAccess = ability.can( Action.DatasetReadManyAccess, DatasetClass, @@ -251,11 +250,6 @@ export class DatasetsV4Controller { }, ]; } - } else if (canViewOwner) { - filter.where = { - ...filter.where, - ownerGroup: { $in: user.currentGroups }, - }; } } @@ -495,17 +489,10 @@ export class DatasetsV4Controller { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); if (canViewAccess) { fields.userGroups = fields.userGroups ?? []; fields.userGroups.push(...user.currentGroups); - } else if (canViewOwner) { - fields.ownerGroup = fields.ownerGroup ?? []; - fields.ownerGroup.push(...user.currentGroups); } } @@ -567,15 +554,9 @@ export class DatasetsV4Controller { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); if (canViewAccess) { fields.userGroups?.push(...user.currentGroups); - } else if (canViewOwner) { - fields.ownerGroup?.push(...user.currentGroups); } } @@ -769,7 +750,7 @@ Set \`content-type\` header to \`application/merge-patch+json\` if you would lik description: "Id of the dataset to modify", type: String, }) - @ApiConsumes("application/merge-patch+json", "application/json") + @ApiConsumes("application/json", "application/merge-patch+json") @ApiBody({ description: "Fields that needs to be updated in the dataset. Only the fields that needs to be updated have to be passed in.", diff --git a/src/datasets/dto/create-relationship.dto.ts b/src/datasets/dto/create-relationship.dto.ts index 8054c330e..c1d24cee1 100644 --- a/src/datasets/dto/create-relationship.dto.ts +++ b/src/datasets/dto/create-relationship.dto.ts @@ -1,20 +1,54 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; +import { IsOptional, IsString, Validate } from "class-validator"; +import { RelatedIdentifierMatchesType } from "../utils/related-identifier-validator.util"; export class CreateRelationshipDto { @ApiProperty({ type: String, required: true, - description: "Persistent identifier of the related dataset.", + description: + "Identifier of the related entity (e.g. 'https://example.org/datasets/123', '10.1016/j.epsl.2011.11.037', 'arXiv:0706.0001').", }) + @Validate(RelatedIdentifierMatchesType) @IsString() - readonly pid: string; + readonly identifier: string; - @ApiProperty({ + @ApiPropertyOptional({ type: String, - required: true, - description: "Relationship between this dataset and the related one.", + description: + "Type of the related identifier (e.g., 'URL', 'DOI', 'arXiv', 'Other'). We may use 'Local' for SciCat identifiers", + default: "Other", + }) + @IsString() + @IsOptional() + readonly identifierType?: string; + + @ApiPropertyOptional({ + type: String, + description: + "Relationship between this dataset and the related entity (e.g., 'IsReferencedBy', 'IsSupplementTo', 'IsCitedBy').", + default: "IsReferencedBy", + }) + @IsString() + @IsOptional() + readonly relationship?: string; + + @ApiPropertyOptional({ + type: String, + description: + "Type of the related entity (e.g., 'Dataset', 'Logbook', 'Other').", + default: "Other", + }) + @IsString() + @IsOptional() + readonly entityType?: string; + + @ApiPropertyOptional({ + type: String, + description: + "Identifier of the related entity in the external system. Not used for SciCat-internal relationships.", }) @IsString() - relationship: string; + @IsOptional() + readonly externalId?: string; } diff --git a/src/datasets/dto/update-dataset-obsolete.dto.ts b/src/datasets/dto/update-dataset-obsolete.dto.ts index 8482d650f..00ddd66f9 100644 --- a/src/datasets/dto/update-dataset-obsolete.dto.ts +++ b/src/datasets/dto/update-dataset-obsolete.dto.ts @@ -11,6 +11,7 @@ import { IsDateString, IsEmail, IsInt, + IsNotEmpty, IsNumber, IsObject, IsOptional, @@ -22,7 +23,6 @@ import { import { TechniqueClass } from "../schemas/technique.schema"; import { Type, Transform } from "class-transformer"; import { CreateTechniqueDto } from "./create-technique.dto"; -import { RelationshipClass } from "../schemas/relationship.schema"; import { CreateRelationshipDto } from "./create-relationship.dto"; import { LifecycleClass } from "../schemas/lifecycle.schema"; import { encodeScientificMetadataKeys } from "src/common/utils"; @@ -75,6 +75,7 @@ export class UpdateDatasetObsoleteDto extends OwnableDto { "Absolute file path on file server containing the files of this dataset, e.g. /some/path/to/sourcefolder. In case of a single file dataset, e.g. HDF5 data, it contains the path up to, but excluding the filename. Trailing slashes are removed.", }) @IsString() + @IsNotEmpty() readonly sourceFolder: string; @ApiProperty({ @@ -244,17 +245,18 @@ export class UpdateDatasetObsoleteDto extends OwnableDto { // it needs to be discussed if this fields is managed by the user or by the system @ApiProperty({ - type: "array", - items: { $ref: getSchemaPath(RelationshipClass) }, + type: CreateRelationshipDto, required: false, + isArray: true, default: [], - description: "Stores the relationships with other datasets.", + description: `Array of relationships with other entities (possibly external to the catalog). + Inspired by DataCite's relatedIdentifier schema: https://datacite-metadata-schema.readthedocs.io/en/4.7/properties/relatedidentifier/`, }) @IsArray() @IsOptional() @ValidateNested({ each: true }) @Type(() => CreateRelationshipDto) - readonly relationships?: RelationshipClass[]; + readonly relationships?: CreateRelationshipDto[]; @ApiProperty({ type: LifecycleClass, diff --git a/src/datasets/dto/update-dataset.dto.ts b/src/datasets/dto/update-dataset.dto.ts index 4ddf008ab..57848a7a0 100644 --- a/src/datasets/dto/update-dataset.dto.ts +++ b/src/datasets/dto/update-dataset.dto.ts @@ -11,6 +11,7 @@ import { IsDateString, IsEmail, IsInt, + IsNotEmpty, IsNumber, IsObject, IsOptional, @@ -22,7 +23,6 @@ import { import { TechniqueClass } from "../schemas/technique.schema"; import { Transform, Type } from "class-transformer"; import { CreateTechniqueDto } from "./create-technique.dto"; -import { RelationshipClass } from "../schemas/relationship.schema"; import { CreateRelationshipDto } from "./create-relationship.dto"; import { LifecycleClass } from "../schemas/lifecycle.schema"; import { HistoryClass } from "../schemas/history.schema"; @@ -77,6 +77,7 @@ export class UpdateDatasetDto extends OwnableDto { "Absolute file path on file server containing the files of this dataset, e.g. /some/path/to/sourcefolder. In case of a single file dataset, e.g. HDF5 data, it contains the path up to, but excluding the filename. Trailing slashes are removed.", }) @IsString() + @IsNotEmpty() readonly sourceFolder: string; @ApiProperty({ @@ -247,17 +248,18 @@ export class UpdateDatasetDto extends OwnableDto { // it needs to be discussed if this fields is managed by the user or by the system @ApiProperty({ - type: RelationshipClass, + type: CreateRelationshipDto, required: false, isArray: true, default: [], - description: "Stores the relationships with other datasets.", + description: `Array of relationships with other entities (possibly external to the catalog). + Inspired by DataCite's relatedIdentifier schema: https://datacite-metadata-schema.readthedocs.io/en/4.7/properties/relatedidentifier/`, }) @IsArray() @IsOptional() @ValidateNested({ each: true }) @Type(() => CreateRelationshipDto) - readonly relationships?: RelationshipClass[]; + readonly relationships?: CreateRelationshipDto[]; @ApiProperty({ type: LifecycleClass, diff --git a/src/datasets/interfaces/dataset-filters.interface.ts b/src/datasets/interfaces/dataset-filters.interface.ts index ebbe4ac1f..7d1954482 100644 --- a/src/datasets/interfaces/dataset-filters.interface.ts +++ b/src/datasets/interfaces/dataset-filters.interface.ts @@ -43,6 +43,10 @@ export interface IDatasetFields { [key: string]: unknown; } +export type IDatasetOpenSearchPipeline = Omit & { + openSearchIdList?: string[]; +}; + export type IDatasetScopesV4 = | IOrigDatablockFiltersV4 | IFiltersV4 diff --git a/src/datasets/schemas/dataset.schema.ts b/src/datasets/schemas/dataset.schema.ts index 8f4f8a15e..9a8af6c39 100644 --- a/src/datasets/schemas/dataset.schema.ts +++ b/src/datasets/schemas/dataset.schema.ts @@ -290,8 +290,8 @@ export class DatasetClass extends OwnableClass { items: { $ref: getSchemaPath(RelationshipClass) }, required: false, default: [], - description: - "Array of relationships with other datasets. It contains relationship type and destination dataset", + description: `Array of relationships with other entities (possibly external to the catalog). + Inspired by DataCite's relatedIdentifier schema: https://datacite-metadata-schema.readthedocs.io/en/4.7/properties/relatedidentifier/`, }) @Prop({ type: [RelationshipSchema], required: false, default: [] }) relationships?: RelationshipClass[]; @@ -481,3 +481,5 @@ export class DatasetClass extends OwnableClass { export const DatasetSchema = SchemaFactory.createForClass(DatasetClass); DatasetSchema.index({ "$**": "text" }); +DatasetSchema.index({ "relationships.identifier": 1 }); +DatasetSchema.index({ "relationships.externalId": 1 }); diff --git a/src/datasets/schemas/relationship.schema.ts b/src/datasets/schemas/relationship.schema.ts index 200f0e5cb..63ff5b848 100644 --- a/src/datasets/schemas/relationship.schema.ts +++ b/src/datasets/schemas/relationship.schema.ts @@ -1,5 +1,5 @@ import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { ApiProperty } from "@nestjs/swagger"; +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { Document } from "mongoose"; export type RelationshipDocument = RelationshipClass & Document; @@ -9,18 +9,46 @@ export class RelationshipClass { @ApiProperty({ type: String, required: true, - description: "Persistent identifier of the related dataset.", + description: + "Identifier of the related entity (e.g. 'https://example.org/datasets/123', '10.1016/j.epsl.2011.11.037', 'arXiv:0706.0001')", }) @Prop({ type: String, required: true }) - pid: string; + identifier: string; @ApiProperty({ type: String, - required: true, - description: "Relationship between this dataset and the related one.", + description: + "Type of the related `identifier` (e.g., 'URL', 'DOI', 'arXiv', 'Other'). We may use 'Local' for SciCat identifiers", + default: "Other", }) - @Prop({ type: String, required: true }) + @Prop({ type: String, default: "Other" }) + identifierType: string; + + @ApiProperty({ + type: String, + description: + "Relationship between this dataset and the related entity (e.g., 'IsReferencedBy', 'IsSupplementTo', 'IsCitedBy').", + default: "IsReferencedBy", + }) + @Prop({ type: String, default: "IsReferencedBy" }) relationship: string; + + @ApiProperty({ + type: String, + description: + "Type of the related entity (e.g., 'Dataset', 'Logbook', 'Other').", + default: "Other", + }) + @Prop({ type: String, default: "Other" }) + entityType: string; + + @ApiPropertyOptional({ + type: String, + description: + "Identifier of the related entity in the external system. Not used for SciCat-internal relationships.", + }) + @Prop({ type: String, required: false }) + externalId?: string; } export const RelationshipSchema = diff --git a/src/datasets/utils/related-identifier-validator.util.spec.ts b/src/datasets/utils/related-identifier-validator.util.spec.ts new file mode 100644 index 000000000..b3fd04690 --- /dev/null +++ b/src/datasets/utils/related-identifier-validator.util.spec.ts @@ -0,0 +1,55 @@ +import { CreateRelationshipDto } from "../dto/create-relationship.dto"; +import { RelatedIdentifierMatchesType } from "./related-identifier-validator.util"; +import { ValidationArguments } from "class-validator"; + +describe("RelatedIdentifierMatchesType", () => { + const validator = new RelatedIdentifierMatchesType(); + + const makeArgs = ( + object: Partial, + ): ValidationArguments => + ({ + targetName: "CreateRelationshipDto", + object, + property: "identifier", + value: object.identifier, + constraints: [], + }) as ValidationArguments; + + it("validates URL when identifierType is URL", () => { + expect( + validator.validate( + "https://example.org/datasets/123", + makeArgs({ + identifier: "https://example.org/datasets/123", + identifierType: "URL", + }), + ), + ).toBe(true); + }); + + it("rejects invalid URL when identifierType is URL", () => { + expect( + validator.validate( + "noturl/datasets/123", + makeArgs({ + identifier: "noturl/datasets/123", + identifierType: "URL", + }), + ), + ).toBe(false); + }); + + it("accepts any string when identifierType is missing", () => { + expect( + validator.validate("anything123", makeArgs({ identifier: "Other" })), + ).toBe(true); + }); + + it("provides a descriptive default message", () => { + const message = validator.defaultMessage( + makeArgs({ identifier: "foo", identifierType: "URL" }), + ); + expect(message).toContain("URL"); + }); +}); diff --git a/src/datasets/utils/related-identifier-validator.util.ts b/src/datasets/utils/related-identifier-validator.util.ts new file mode 100644 index 000000000..3d16ae954 --- /dev/null +++ b/src/datasets/utils/related-identifier-validator.util.ts @@ -0,0 +1,36 @@ +import { Injectable } from "@nestjs/common"; +import { + ValidatorConstraint, + ValidatorConstraintInterface, + ValidationArguments, + isURL, +} from "class-validator"; +import { CreateRelationshipDto } from "../dto/create-relationship.dto"; + +@Injectable() +@ValidatorConstraint({ + name: "relatedIdentifierMatchesType", + async: false, +}) +export class RelatedIdentifierMatchesType implements ValidatorConstraintInterface { + validate(value: unknown, args: ValidationArguments) { + if (typeof value !== "string") { + return false; + } + + const dto = args.object as Partial; + + switch (dto.identifierType) { + case "URL": + return isURL(value); + default: + return true; + } + } + + defaultMessage(args: ValidationArguments) { + const dto = args.object as Partial; + const type = dto.identifierType ?? "the configured type"; + return `identifier must be a valid ${type} when identifierType is set to '${dto.identifierType}'.`; + } +} diff --git a/src/elastic-search/Elasticsearch_guide.md b/src/elastic-search/Elasticsearch_guide.md deleted file mode 100644 index 1b43155cd..000000000 --- a/src/elastic-search/Elasticsearch_guide.md +++ /dev/null @@ -1,211 +0,0 @@ -# Getting started - -To be able to start application with Elasticsearch you will need to: - -1. Start with `npm prepare:local` to executes docker-compose file which pull and run Elasticsearch cluster as a docker container. -2. Start the application with `npm run start` - -# Check the .env file - -Following environment variables are required to run Elasticsearch with Scicat Backend: - -| `Variables` | Values | Description | -| ------------------------ | :--------------------- | :------------------------------------------------------------------------------------------------------------- | -| `ELASTICSEARCH_ENABLED` | `yes` or `no` | Flag to enable/disable the ElasticSearch service | -| `ES_HOST ` | https://localhost:9200 | Use `http` if `xpack.security.enabled` set to `false` | -| `ES_USERNAME` (optional) | elastic | Elasticsearch cluster username. Can be customized with docker image environment values with `ELASTIC_USERNAME` | -| `ES_PASSWORD` | password | Elasticsearch cluster password. Can be customized with docker image environment values `ELASTIC_PASSWORD` | -| `MONGODB_COLLECTION ` | Dataset | Collection name to be mapped into specified Elasticsearch index | -| `ES_MAX_RESULT ` | 210000 | Maximum records can be indexed into Elasticsearch. If not set, default is `10000` | -| `ES_FIELDS_LIMIT ` | 400000 | The total number of fields in an index. If not set, default is `1000` | -| `ES_INDEX ` | dataset | Setting default index for the application | -| `ES_REFRESH ` | wait_for | Wait for the change to become visible - CRUD actions | -| | | - -## \*\* NOTE \*\* - -`ES_REFRESH="wait_for"` is used for better testing flow. For production it should be set to false. Detailed docs about this setting can be found: [docs-refresh](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-refresh.html) - -# Steps to synchronize data with Elasitcsearch - -To enable search queries in Elasticsearch, you should adhere to the following steps: - -1. Open Swagger page `http://localhost:3000/explorer`, Authorize with `admin` token -2. Open elastic-search endpoints and execute `create-index`. - _**NOTE:**_ This step can be skipped if you want to use default index `dataset` -3. execute `sync-database` to sync data into the given index. - -If you see the following response, it means Elasticsearch is ready for use. - -``` -{ - "total": 21670, - "failed": 0, - "retry": 0, - "successful": 21670, - "noop": 0, - "time": 4777, - "bytes": 279159021, - "aborted": false -} -``` - -# Index, analysis and mapping settings - -Index settings in Elasticsearch are used to define various configurations and behaviors for an index. Index settings are vital for optimizing Elasticsearch's performance, relevance of search results, and resource management, ensuring that the index operates efficiently and effectively according to the specific needs of the application using it. - -Pre-defined index settings & dynamic mapping for nested objects can be found `/src/elastic-search/configuration/indexSetting.ts` - -Fields to be mapped into Elasticsearch index can be found `/src/elastic-search/configuration/datasetFieldMapping.ts` - -**Index settings:** - -``` -export const defaultElasticSettings = { - index: { - max_result_window: process.env.ES_MAX_RESULT || 2000000, - number_of_replicas: 0, - mapping: { - total_fields: { - limit: process.env.ES_FIELDS_LIMIT || 2000000, - }, - nested_fields: { - limit: 1000, - }, - }, - }, - analysis: { - analyzer: { - autocomplete: { - tokenizer: "autocomplete", - filter: ["lowercase"], - }, - autocomplete_search: { - tokenizer: "lowercase", - }, - }, - tokenizer: { - autocomplete: autocomplete_tokenizer, - }, - }, -} as IndicesIndexSettingsAnalysis; -``` - -| `Object` | Description | -| ----------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `index` | It contains settings that determine how an Elasticsearch index works, like how many results you can get from a search and how many copies of the data it should store. More details in [index modules](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html) | -| `index.max_result_window` | Determines the maximum number of documents returned in a query. `Default is 10000` | -| `index.number_of_replicas` | Sets the number of replica shards. `Default is 1` | -| `index.mapping.total_fields.limit` | Sets the maximum number of fields an index can have. `Default is 1000` | -| `index.mapping.nested_fields.limit` | Sets the maximum number of nested fields. `Default is 50` | -| `analysis` | It defines how text data is processed before it is indexed, including custom analyzers and tokenizers which control the conversion of text into tokens or terms. More details in [analyzer](https://www.elastic.co/guide/en/elasticsearch/reference/current/analyzer.html) and [analysis](https://www.elastic.co/guide/en/elasticsearch/reference/8.8/analysis.html) | - -
- -**Dynamic mapping:** - -Dynamic mapping is currently only used for scientific field. More details in [Dynamic template](https://www.elastic.co/guide/en/elasticsearch/reference/8.8/dynamic-templates.html) - -``` -export const dynamic_template: Record[] = [ - { - string_as_keyword: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "string", - mapping: { - type: "keyword", - ignore_above: 256, - }, - }, - }, - { - long_as_double: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "long", - mapping: { - type: "double", - coerce: true, - ignore_malformed: true, - }, - }, - }, - { - date_as_keyword: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "date", - mapping: { - type: "keyword", - ignore_above: 256, - }, - }, - }, -]; -``` - -# APIs - -`NOTE: All requests require admin permissions.` - -For search query integration it is suggested to use client search service directly, which can be found `/src/elastic-search/elastic-search.service.ts` - -**Following table is existing controller endpoints:** - -| endpoint | parameters | request | description | -| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ------------------------------------------------- | -| /api/v3/elastic-search/create-index?index= | `string` | query | Create an index with this name | -| /api/v3/elastic-search/sync-database?index= | `string` | query | Sync datasets into elastic search with this index | -| /api/v3/elastic-search/search | `{ "text": "", "ownerGroup": [], "creationLocation": [], "type": [], "keywords": [], "isPublished": false, "scientific": [{"lhs": "", "relation": "", "rhs": 0, "unit": ""}]}` | body | Search query | -| /api/v3/elastic-search/delete-index | `string` | query | Delete an index with this name | -| /api/v3/elastic-search/get-index | `string` | query | Get an index settings with this name | -| /api/v3/elastic-search/update-index | `to be updated` | to be updated | to be updated | - -# Setting up a local Elasticsearch cluster - -## Docker Configuration - -For local development, you can spin up an Elasticsearch cluster using Docker with the following configuration: - -_Elasticsearch image configuration can be found in `./CI/E2E/docker-compose-local.yaml`_ - -``` -es01: - image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2 - ports: - - 9200:9200 - environment: - - xpack.security.enabled=false - - node.name=es01 - - ES_JAVA_OPTS=-Xms2g -Xmx2g - - cluster.name=es-cluster - - cluster.initial_master_nodes=es01 - - ELASTIC_PASSWORD=password - - bootstrap.memory_lock=true - mem_limit: 4g - ulimits: - memlock: - soft: -1 - hard: -1 -``` - -| **`Settings`** | **`Description`** | -| ---------------------------- | -------------------------------------------------------------------------------------- | -| Image Version | Docker image for Elasticsearch: `docker.elastic.co/elasticsearch/elasticsearch:8.8.2`. | -| Port | Container-to-host port mapping: `9200:9200`. | -| mem_limit | Maximum container memory, influenced by `ES_JAVA_OPTS`. | -| ulimits.memlock (soft, hard) | Memory locking limits: `-1` for unlimited. | -| **`Variables`** | **`Description`** | -| xpack.security.enabled | Toggle for Elasticsearch security; `false` disables authentication for development. | -| node.name | Unique Elasticsearch node name; essential for cluster node identification. | -| ES_JAVA_OPTS | JVM heap memory settings for Elasticsearch performance (e.g., `-Xms2g -Xmx2g`). | -| cluster.name | Name of the Elasticsearch cluster for node grouping. | -| ELASTIC_PASSWORD | Password for the 'elastic' user; not needed if security is disabled. | -| bootstrap.memory_lock | Prevents swapping Elasticsearch memory to disk when enabled. | - -## Using Helm for Kubernetes - -For those looking to deploy on Kubernetes, refer to the official [Helm chart documentation](https://github.com/elastic/helm-charts/tree/main/elasticsearch) for Elasticsearch. Helm charts provide a more production-ready setup and can manage complex configurations. - -**More configuration information:** - -- [More complicated examples with docker-compose configuration](https://www.elastic.co/guide/en/elasticsearch/reference/8.8/docker.html) -- [More service configures for production](https://www.elastic.co/guide/en/elasticsearch/reference/8.8/important-settings.html) diff --git a/src/elastic-search/configuration/datasetFieldMapping.ts b/src/elastic-search/configuration/datasetFieldMapping.ts deleted file mode 100644 index bed10c389..000000000 --- a/src/elastic-search/configuration/datasetFieldMapping.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { MappingObject } from "../interfaces/mappingInterface.type"; - -export const datasetMappings: MappingObject = { - description: { - type: "text", - analyzer: "autocomplete", - search_analyzer: "autocomplete_search", - fields: { - keyword: { - type: "keyword", - ignore_above: 256, - }, - }, - }, - datasetName: { - type: "text", - analyzer: "autocomplete", - search_analyzer: "autocomplete_search", - fields: { - keyword: { - type: "keyword", - ignore_above: 256, - }, - }, - }, - pid: { - type: "keyword", - ignore_above: 256, - }, - creationTime: { - type: "date", - }, - endTime: { - type: "date", - }, - scientificMetadata: { - type: "nested", - dynamic: true, - properties: {}, - }, - history: { - type: "nested", - dynamic: false, - }, - proposalIds: { - type: "keyword", - ignore_above: 256, - }, - sampleIds: { - type: "keyword", - ignore_above: 256, - }, - instrumentIds: { - type: "keyword", - ignore_above: 256, - }, - sourceFolder: { - type: "keyword", - ignore_above: 256, - }, - isPublished: { - type: "boolean", - }, - type: { - type: "keyword", - ignore_above: 256, - }, - keywords: { - type: "keyword", - ignore_above: 256, - }, - creationLocation: { - type: "keyword", - ignore_above: 256, - }, - ownerGroup: { - type: "keyword", - ignore_above: 256, - }, - accessGroups: { - type: "keyword", - ignore_above: 256, - }, - sharedWith: { - type: "keyword", - ignore_above: 256, - }, - ownerEmail: { - type: "keyword", - ignore_above: 256, - }, - size: { - type: "long", - }, - runNumber: { - type: "keyword", - ignore_above: 256, - }, - // NOTE: below fields are for backward compatibility - // and should be removed when obsolete dto is removed - proposalId: { - type: "keyword", - ignore_above: 256, - }, - sampleId: { - type: "keyword", - ignore_above: 256, - }, - instrumentId: { - type: "keyword", - ignore_above: 256, - }, -}; diff --git a/src/elastic-search/configuration/indexSetting.ts b/src/elastic-search/configuration/indexSetting.ts deleted file mode 100644 index 07ce39ac6..000000000 --- a/src/elastic-search/configuration/indexSetting.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { - AnalysisEdgeNGramTokenizer, - AnalysisPatternReplaceCharFilter, - IndicesIndexSettingsAnalysis, - MappingDynamicTemplate, -} from "@elastic/elasticsearch/lib/api/types"; - -//Tokenizers -export const autocomplete_tokenizer: AnalysisEdgeNGramTokenizer = { - type: "edge_ngram", - min_gram: 2, - max_gram: 40, - token_chars: ["letter", "digit", "symbol", "punctuation"], -}; - -//Filters -export const special_character_filter: AnalysisPatternReplaceCharFilter = { - pattern: "[^A-Za-z0-9]", - type: "pattern_replace", - replacement: "", -}; - -//Dynamic templates -export const dynamic_template: Record[] = [ - // NOTE: date as keyword is temporary solution for date format inconsistency issue in the scientificMetadata field - { - date_as_keyword: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "date", - mapping: { - type: "keyword", - }, - }, - }, - { - long_as_double: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "long", - mapping: { - type: "double", - coerce: true, - ignore_malformed: true, - }, - }, - }, - { - double_as_double: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "double", - mapping: { - type: "double", - coerce: true, - ignore_malformed: true, - }, - }, - }, - { - string_as_keyword_level2: { - path_match: "scientificMetadata.*.*", - match_mapping_type: "string", - mapping: { - type: "text", - analyzer: "case_sensitive", - search_analyzer: "case_sensitive", - fields: { - keyword: { - type: "keyword", - ignore_above: 256, - }, - }, - }, - }, - }, - { - string_as_keyword_level1: { - path_match: "scientificMetadata.*", - match_mapping_type: "string", - mapping: { - type: "text", - analyzer: "case_sensitive", - search_analyzer: "case_sensitive", - fields: { - keyword: { - type: "keyword", - ignore_above: 256, - }, - }, - }, - }, - }, -]; - -//Index Settings -export const defaultElasticSettings = { - index: { - max_result_window: process.env.ES_MAX_RESULT || 2000000, - number_of_replicas: 0, - mapping: { - total_fields: { - limit: process.env.ES_FIELDS_LIMIT || 2000000, - }, - nested_fields: { - limit: 1000, - }, - }, - }, - analysis: { - analyzer: { - autocomplete: { - tokenizer: "autocomplete", - filter: ["lowercase"], - }, - autocomplete_search: { - tokenizer: "lowercase", - }, - case_sensitive: { - type: "custom", - tokenizer: "standard", - filter: [], - }, - }, - tokenizer: { - autocomplete: autocomplete_tokenizer, - }, - }, -} as IndicesIndexSettingsAnalysis; diff --git a/src/elastic-search/dto/create-index.dto.ts b/src/elastic-search/dto/create-index.dto.ts deleted file mode 100644 index 3f63ac65d..000000000 --- a/src/elastic-search/dto/create-index.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; - -export class CreateIndexDto { - @ApiProperty({ - type: String, - required: true, - default: "dataset", - description: "Create an index with this name", - }) - @IsString() - readonly index: string; -} diff --git a/src/elastic-search/dto/delete-index.dto.ts b/src/elastic-search/dto/delete-index.dto.ts deleted file mode 100644 index 433511d9b..000000000 --- a/src/elastic-search/dto/delete-index.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; - -export class DeleteIndexDto { - @ApiProperty({ - type: String, - required: true, - default: "dataset", - description: "Delete an index with this name", - }) - @IsString() - readonly index: string; -} diff --git a/src/elastic-search/dto/get-index.dto.ts b/src/elastic-search/dto/get-index.dto.ts deleted file mode 100644 index 3ce9849ad..000000000 --- a/src/elastic-search/dto/get-index.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; - -export class GetIndexDto { - @ApiProperty({ - type: String, - required: true, - default: "dataset", - description: "Get an index with this name", - }) - @IsString() - readonly index: string; -} diff --git a/src/elastic-search/dto/index.ts b/src/elastic-search/dto/index.ts deleted file mode 100644 index ea3e4ea1c..000000000 --- a/src/elastic-search/dto/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CreateIndexDto } from "../dto/create-index.dto"; -import { DeleteIndexDto } from "../dto/delete-index.dto"; -import { GetIndexDto } from "../dto/get-index.dto"; -import { SyncDatabaseDto } from "../dto/sync-data.dto"; -import { UpdateIndexDto } from "../dto/update-index.dto"; - -export class ElasticSearchActions { - createIndex: CreateIndexDto; - deleteIndex: DeleteIndexDto; - updateIndex: UpdateIndexDto; - syncDatabase: SyncDatabaseDto; - getIndexSettings: GetIndexDto; -} diff --git a/src/elastic-search/dto/search.dto.ts b/src/elastic-search/dto/search.dto.ts deleted file mode 100644 index 13270eba5..000000000 --- a/src/elastic-search/dto/search.dto.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsArray, IsOptional } from "class-validator"; - -export class SearchDto { - @ApiProperty({ - type: String, - required: false, - default: "", - description: "text query", - }) - readonly text: string; - - @ApiProperty({ - type: Array, - required: false, - default: [], - description: "ownerGroup", - }) - @IsOptional() - readonly ownerGroup: []; - - @ApiProperty({ - type: Array, - required: false, - default: [], - description: "creationLocation", - }) - @IsOptional() - readonly creationLocation: []; - - @ApiProperty({ - type: Array, - required: false, - default: [], - description: "type", - }) - @IsOptional() - readonly type: []; - - @ApiProperty({ - type: Array, - required: false, - default: [], - description: "keywords", - }) - @IsOptional() - readonly keywords: []; - - @ApiProperty({ - type: Boolean, - required: false, - default: false, - description: "isPublished", - }) - @IsOptional() - readonly isPublished: boolean; - - @ApiProperty({ - type: Array, - items: { - type: "object", - properties: { - lhs: { type: "string" }, - relation: { type: "string" }, - rhs: { - type: "number", - description: "This can be either a number or a string", - }, - unit: { type: "string" }, - }, - }, - required: false, - default: [ - { - lhs: "", - relation: "", - rhs: 0, - unit: "", - }, - ], - description: "scientificMetadata condition", - }) - @IsOptional() - @IsArray() - readonly scientific: Array<{ - lhs: string; - relation: string; - rhs: number | string; - unit: string; - }>; -} diff --git a/src/elastic-search/dto/sync-data.dto.ts b/src/elastic-search/dto/sync-data.dto.ts deleted file mode 100644 index 1bdf3ff34..000000000 --- a/src/elastic-search/dto/sync-data.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; - -export class SyncDatabaseDto { - @ApiProperty({ - type: String, - required: true, - default: "dataset", - description: "Sync datasets into elastic search with this index", - }) - @IsString() - readonly index: string; -} diff --git a/src/elastic-search/dto/update-index.dto.ts b/src/elastic-search/dto/update-index.dto.ts deleted file mode 100644 index b6f264e24..000000000 --- a/src/elastic-search/dto/update-index.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; - -export class UpdateIndexDto { - @ApiProperty({ - type: String, - required: true, - default: "dataset", - description: "Update an index with this name", - }) - @IsString() - readonly index: string; -} diff --git a/src/elastic-search/elastic-search.controller.ts b/src/elastic-search/elastic-search.controller.ts deleted file mode 100644 index de2498da6..000000000 --- a/src/elastic-search/elastic-search.controller.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { - Controller, - HttpCode, - HttpStatus, - Post, - Body, - Get, - Query, - UseInterceptors, - UseGuards, -} from "@nestjs/common"; -import { ApiTags, ApiBearerAuth, ApiBody, ApiResponse } from "@nestjs/swagger"; -import { Action } from "src/casl/action.enum"; -import { AppAbility } from "src/casl/casl-ability.factory"; -import { CheckPolicies } from "src/casl/decorators/check-policies.decorator"; -import { PoliciesGuard } from "src/casl/guards/policies.guard"; -import { DatasetsService } from "src/datasets/datasets.service"; -import { SubDatasetsPublicInterceptor } from "src/datasets/interceptors/datasets-public.interceptor"; -import { IDatasetFields } from "src/datasets/interfaces/dataset-filters.interface"; -import { ElasticSearchActions } from "./dto"; -import { CreateIndexDto } from "./dto/create-index.dto"; -import { DeleteIndexDto } from "./dto/delete-index.dto"; -import { GetIndexDto } from "./dto/get-index.dto"; - -import { SearchDto } from "./dto/search.dto"; -import { SyncDatabaseDto } from "./dto/sync-data.dto"; -import { UpdateIndexDto } from "./dto/update-index.dto"; -import { ElasticSearchService } from "./elastic-search.service"; - -@ApiBearerAuth() -@ApiTags("elastic-search") -@Controller("elastic-search") -export class ElasticSearchServiceController { - constructor( - private readonly elasticSearchService: ElasticSearchService, - private readonly datasetService: DatasetsService, - ) {} - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.CREATED) - @ApiResponse({ - status: HttpStatus.CREATED, - description: "Create index", - }) - @Post("/create-index") - async createIndex(@Query() { index }: CreateIndexDto) { - const esIndex = index.trim(); - - return this.elasticSearchService.createIndex(esIndex); - } - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.OK) - @ApiResponse({ - status: 200, - description: "Sync data to the index", - }) - @Post("/sync-database") - async syncDatabase(@Query() { index }: SyncDatabaseDto) { - const esIndex = index.trim(); - const collectionData = await this.datasetService.getDatasetsWithoutId(); - - return this.elasticSearchService.syncDatabase(collectionData, esIndex); - } - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.OK) - @UseInterceptors(SubDatasetsPublicInterceptor) - @ApiBody({ - type: SearchDto, - }) - @ApiResponse({ - status: 200, - description: "Search with elasticsearch to get restuls in PIDs", - }) - @Post("/search") - async fetchESResults(@Body() searchDto: IDatasetFields) { - return this.elasticSearchService.search(searchDto); - } - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.OK) - @ApiResponse({ - status: 200, - description: "Delete index", - }) - @Post("/delete-index") - async deleteIndex(@Query() { index }: DeleteIndexDto) { - const esIndex = index.trim(); - - return this.elasticSearchService.deleteIndex(esIndex); - } - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.OK) - @ApiResponse({ - status: 200, - description: "Get current index setting", - }) - @Get("/get-index") - async getIndex(@Query() { index }: GetIndexDto) { - const esIndex = index.trim(); - - return this.elasticSearchService.getIndexSettings(esIndex); - } - - @UseGuards(PoliciesGuard) - @CheckPolicies("elastic-search", (ability: AppAbility) => - ability.can(Action.Manage, ElasticSearchActions), - ) - @HttpCode(HttpStatus.OK) - @ApiResponse({ - status: 200, - description: "Update index to the latest settings", - }) - @Post("/update-index") - async updateIndex(@Query() { index }: UpdateIndexDto) { - const esIndex = index.trim(); - - return this.elasticSearchService.updateIndex(esIndex); - } -} diff --git a/src/elastic-search/elastic-search.service.ts b/src/elastic-search/elastic-search.service.ts deleted file mode 100644 index f6743ec38..000000000 --- a/src/elastic-search/elastic-search.service.ts +++ /dev/null @@ -1,432 +0,0 @@ -import { - HttpException, - HttpStatus, - Injectable, - Logger, - OnModuleInit, -} from "@nestjs/common"; - -import { Client } from "@elastic/elasticsearch"; -import { SearchQueryService } from "./providers/query-builder.service"; -import { - SearchRequest, - AggregationsAggregate, - SortOrder, -} from "@elastic/elasticsearch/lib/api/types"; -import { IDatasetFields } from "src/datasets/interfaces/dataset-filters.interface"; -import { - defaultElasticSettings, - dynamic_template, -} from "./configuration/indexSetting"; -import { datasetMappings } from "./configuration/datasetFieldMapping"; -import { - DatasetClass, - DatasetDocument, -} from "src/datasets/schemas/dataset.schema"; -import { ConfigService } from "@nestjs/config"; -import { sleep } from "src/common/utils"; -import { - initialSyncTransform, - transformFacets, - addValueType, -} from "./helpers/utils"; - -import { SortFields } from "./providers/fields.enum"; - -@Injectable() -export class ElasticSearchService implements OnModuleInit { - private esService: Client; - private host: string; - private username: string; - private password: string; - private refresh: "false" | "wait_for"; - public defaultIndex: string; - public esEnabled: boolean; - public connected = false; - - constructor( - private readonly searchService: SearchQueryService, - private readonly configService: ConfigService, - ) { - this.host = this.configService.get("elasticSearch.host") || ""; - this.username = - this.configService.get("elasticSearch.username") || ""; - this.password = - this.configService.get("elasticSearch.password") || ""; - this.esEnabled = - this.configService.get("elasticSearch.enabled") === "yes" - ? true - : false; - this.refresh = - this.configService.get<"false" | "wait_for">("elasticSearch.refresh") || - "false"; - - this.defaultIndex = - this.configService.get("elasticSearch.defaultIndex") || ""; - - if ( - this.esEnabled && - (!this.host || !this.username || !this.password || !this.defaultIndex) - ) { - Logger.error( - "Missing ENVIRONMENT variables for elastic search connection", - "ElasticSearch", - ); - } - } - - async onModuleInit() { - if (!this.esEnabled) { - this.connected = false; - return; - } - - try { - await this.retryConnection(3, 3000); - const isIndexExists = await this.isIndexExists(this.defaultIndex); - if (!isIndexExists) { - await this.createIndex(this.defaultIndex); - Logger.log( - `New index ${this.defaultIndex}is created `, - "ElasticSearch", - ); - } - this.connected = true; - Logger.log("Elasticsearch Connected", "ElasticSearch"); - } catch (error) { - Logger.error(error, "onModuleInit failed-> ElasticSearchService"); - } - } - - private async connect() { - const connection = new Client({ - node: this.host, - auth: { - username: this.username, - password: this.password, - }, - tls: { - rejectUnauthorized: false, - }, - }); - await connection.ping(); - this.esService = connection; - } - private async retryConnection(maxRetries: number, interval: number) { - let retryCount = 0; - while (maxRetries > retryCount) { - await sleep(interval); - try { - await this.connect(); - break; - } catch (error) { - Logger.error(`Retry attempt ${retryCount + 1} failed:`, error); - retryCount++; - } - } - - if (retryCount === maxRetries) { - throw new HttpException( - "Max retries reached; check Elasticsearch config.", - HttpStatus.BAD_REQUEST, - ); - } - } - - async isIndexExists(index = this.defaultIndex) { - return await this.esService.indices.exists({ - index, - }); - } - - async createIndex(index = this.defaultIndex) { - try { - await this.esService.indices.create({ - index, - body: { - settings: defaultElasticSettings, - mappings: { - dynamic: true, - dynamic_templates: dynamic_template, - numeric_detection: false, - date_detection: true, - dynamic_date_formats: [ - "yyyy-MM-dd'T'HH:mm:ss|| yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSSZ||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||yyyy-MM-dd'T'HH:mm:ss.SSS", - ], - properties: datasetMappings, - }, - }, - }); - Logger.log( - `Elasticsearch Index Created-> Index: ${index}`, - "Elasticsearch", - ); - return HttpStatus.CREATED; - } catch (error) { - throw new HttpException( - `createIndex failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - async syncDatabase(collection: DatasetClass[], index = this.defaultIndex) { - const indexExists = await this.esService.indices.exists({ index }); - if (!indexExists) { - throw new Error("Index not found"); - } - - const bulkResponse = await this.performBulkOperation(collection, index); - - Logger.log( - JSON.stringify(bulkResponse, null, 0), - "Elasticsearch Data Synchronization Response", - ); - - return bulkResponse; - } - - async getCount(index = this.defaultIndex) { - try { - return await this.esService.count({ index }); - } catch (error) { - throw new HttpException( - `getCount failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async updateIndex(index = this.defaultIndex) { - try { - await this.esService.indices.close({ - index, - }); - await this.esService.indices.putSettings({ - index, - body: { settings: defaultElasticSettings }, - }); - - await this.esService.indices.putMapping({ - index, - dynamic: true, - body: { - properties: datasetMappings, - dynamic_templates: dynamic_template, - }, - }); - - await this.esService.indices.open({ - index, - }); - Logger.log( - `Elasticsearch Index Updated-> Index: ${index}`, - "Elasticsearch", - ); - } catch (error) { - throw new HttpException( - `updateIndex failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async getIndexSettings(index = this.defaultIndex) { - try { - return await this.esService.indices.getSettings({ index }); - } catch (error) { - throw new HttpException( - `getIndexSettings failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async deleteIndex(index = this.defaultIndex) { - try { - await this.esService.indices.delete({ index }); - Logger.log( - `Elasticsearch Index Deleted-> Index: ${index} `, - "Elasticsearch", - ); - return { success: true, message: `Index ${index} deleted` }; - } catch (error) { - throw new HttpException( - `deleteIndex failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async search( - searchParam: IDatasetFields, - limit = 20, - skip = 0, - sort?: Record, - ): Promise<{ totalCount: number; data: (string | undefined)[] }> { - const defaultMinScore = searchParam.text ? 1 : 0; - - try { - const isSortEmpty = !sort || JSON.stringify(sort) === "{}"; - const searchQuery = this.searchService.buildSearchQuery(searchParam); - const searchOptions = { - track_scores: true, - sort: [{ _score: { order: "desc" } }], - query: searchQuery.query, - from: skip, - size: limit, - min_score: defaultMinScore, - track_total_hits: true, - _source: [""], - } as SearchRequest; - - if (!isSortEmpty) { - const sortField = Object.keys(sort)[0]; - const sortDirection = Object.values(sort)[0]; - - // NOTE: To sort datasetName field we need to use datasetName.keyword field, - // as elasticsearch does not have good support for text type field sorting - const isDatasetName = sortField === SortFields.DatasetName; - const fieldForSorting = isDatasetName - ? SortFields.DatasetNameKeyword - : sortField; - - const isNestedField = fieldForSorting.includes( - SortFields.ScientificMetadata, - ); - - if (isNestedField) { - searchOptions.sort = [ - { - [`${SortFields.ScientificMetadataRunNumberValue}`]: { - order: sortDirection, - nested: { - path: SortFields.ScientificMetadata, - }, - }, - }, - ]; - } else { - searchOptions.sort = [ - { [fieldForSorting]: { order: sortDirection } }, - ]; - } - } - - const body = await this.esService.search(searchOptions); - - const totalCount = body.hits.hits.length || 0; - - const data = body.hits.hits.map((item) => item._id || ""); - return { - totalCount, - data, - }; - } catch (error) { - throw new HttpException( - `SearchService || search query issue || -> search ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async aggregate(searchParam: IDatasetFields) { - try { - const searchQuery = this.searchService.buildSearchQuery(searchParam); - const facetPipeline = this.searchService.buildFullFacetPipeline(); - - const searchOptions = { - query: searchQuery.query, - size: 0, - aggs: facetPipeline, - _source: [""], - } as SearchRequest; - - const body = await this.esService.search(searchOptions); - - const transformedFacets = transformFacets( - body.aggregations as AggregationsAggregate, - ); - - return transformedFacets; - } catch (error) { - throw new HttpException( - `SearchService || aggregate query issue || -> aggregate ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - async updateInsertDocument(data: Partial) { - //NOTE: Replace all keys with lower case, also replace spaces and dot with underscore - delete data._id; - const transformedScientificMetadata = addValueType( - data.scientificMetadata as Record, - ); - - const transformedData = { - ...data, - scientificMetadata: transformedScientificMetadata, - }; - try { - await this.esService.index({ - index: this.defaultIndex, - id: data.pid, - document: transformedData, - refresh: this.refresh, - }); - - Logger.log( - `Document Update/inserted-> Document_id: ${data.pid} update/inserted on index: ${this.defaultIndex}`, - "Elasticsearch", - ); - } catch (error) { - throw new HttpException( - `updateDocument failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - async deleteDocument(id: string) { - try { - await this.esService.delete({ - index: this.defaultIndex, - id, - refresh: this.refresh, - }); - Logger.log( - `Document Deleted-> Document_id: ${id} deleted on index: ${this.defaultIndex}`, - "Elasticsearch", - ); - } catch (error) { - throw new HttpException( - `deleteDocument failed-> ElasticSearchService ${error}`, - HttpStatus.BAD_REQUEST, - ); - } - } - - // *** NOTE: below are helper methods *** - - async performBulkOperation(collection: DatasetClass[], index: string) { - const result = await this.esService.helpers.bulk({ - retries: 5, - wait: 10000, - datasource: collection, - onDocument(doc: DatasetClass) { - return [ - { - index: { - _index: index, - _id: doc.pid, - }, - }, - initialSyncTransform(doc), - ]; - }, - onDrop(doc) { - console.debug(`${doc.document.pid}`, doc.error?.reason); - }, - }); - return result; - } -} diff --git a/src/elastic-search/helpers/utils.ts b/src/elastic-search/helpers/utils.ts deleted file mode 100644 index 48817e625..000000000 --- a/src/elastic-search/helpers/utils.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { - AggregationsAggregate, - AggregationsFrequentItemSetsBucketKeys, -} from "@elastic/elasticsearch/lib/api/types"; -import { DatasetClass } from "src/datasets/schemas/dataset.schema"; -import { - IFilter, - ITransformedFullFacets, - nestedQueryObject, - ScientificQuery, -} from "../interfaces/es-common.type"; -import { isObject } from "lodash"; - -export const transformKey = (key: string): string => { - return key.trim().replace(/[.]/g, "\\.").replace(/ /g, "_").toLowerCase(); -}; -export const addValueType = (obj: Record) => { - const newObj: Record = {}; - - for (const [key, value] of Object.entries(obj)) { - const newKey = transformKey(key); - - const isNumberValueType = - typeof (value as Record)?.value === "number"; - const isStringValueType = - typeof (value as Record)?.value === "string"; - - if (isObject(value)) { - if (isNumberValueType) { - (value as Record)["value_type"] = "number"; - } else if (isStringValueType) { - (value as Record)["value_type"] = "string"; - } else { - (value as Record)["value_type"] = "unknown"; - } - } - - newObj[newKey] = value; - } - - return newObj; -}; - -export const transformMiddleKey = (key: string) => { - const parts = key.trim().split("."); - const firstPart = parts[0]; - const lastPart = parts[parts.length - 1]; - - const middlePartRaw = parts.slice(1, parts.length - 1).join("."); - const middlePart = transformKey(middlePartRaw); - - let transformedKey = firstPart; - if (middlePart) { - transformedKey += `.${middlePart}`; - } - transformedKey += `.${lastPart}`; - - return { transformedKey, firstPart, middlePart, lastPart }; -}; - -export const initialSyncTransform = (obj: DatasetClass) => { - const modifedDocInArray = !!obj.scientificMetadata - ? Object.entries(obj.scientificMetadata as Record).map( - ([key, value]) => { - const transformedKey = transformKey(key); - - if (!isObject(value)) { - return [transformedKey, { value: value, unit: "" }]; - } - - if ("value" in value) { - if (typeof value.value === "number") { - return [transformedKey, { ...value, value_type: "number" }]; - } - if (typeof value.value === "string") { - return [transformedKey, { ...value, value_type: "string" }]; - } - } - - return [transformedKey, { ...value, value_type: "unknown" }]; - }, - ) - : []; - - const modifiedDocInObject = { - ...obj, - scientificMetadata: - modifedDocInArray.length > 0 ? Object.fromEntries(modifedDocInArray) : {}, - }; - - return modifiedDocInObject; -}; - -const extractNestedQueryOperationValue = (query: nestedQueryObject) => { - const field = Object.keys(query)[0]; - const operationWithPrefix = Object.keys(query[field])[0]; - - const value = - typeof query[field][operationWithPrefix] === "string" - ? (query[field][operationWithPrefix] as string).trim() - : query[field][operationWithPrefix]; - - const operation = operationWithPrefix.replace("$", ""); - - return { operation, value, field }; -}; - -export const convertToElasticSearchQuery = ( - scientificQuery: ScientificQuery, -): IFilter[] => { - const filters: IFilter[] = []; - - for (const field in scientificQuery) { - const query = scientificQuery[field]; - - if (field === "$and" && Array.isArray(query)) { - query.forEach((query: { $or: nestedQueryObject[] }) => { - const shouldQueries = query.$or.map((orQuery: nestedQueryObject) => { - const { operation, value, field } = - extractNestedQueryOperationValue(orQuery); - const filterType = operation === "eq" ? "term" : "range"; - - // NOTE: if value is not a number, we use keyword field for exact match - const targetField = - typeof value !== "number" ? `${field}.keyword` : field; - return { - [filterType]: { - [targetField]: - operation === "eq" ? value : { [operation]: value }, - }, - }; - }); - filters.push({ - bool: { - should: shouldQueries, - minimum_should_match: 1, - }, - }); - }); - } else if (field === "$or" && Array.isArray(query)) { - const shouldQueries = query.map((query: nestedQueryObject) => { - const { operation, value, field } = - extractNestedQueryOperationValue(query); - const filterType = operation === "eq" ? "term" : "range"; - - // NOTE: if value is not a number, we use keyword field for exact match - const targetField = - typeof value !== "number" ? `${field}.keyword` : field; - return { - [filterType]: { - [targetField]: operation === "eq" ? value : { [operation]: value }, - }, - }; - }); - filters.push({ - bool: { - should: shouldQueries, - minimum_should_match: 1, - }, - }); - } else if ( - Object.keys(query).length > 1 && - !Array.isArray(query) && - isObject(query) - ) { - const { transformedKey, firstPart, middlePart, lastPart } = - transformMiddleKey(field); - - const rangeOps: Record = {}; - - Object.keys(query).forEach((op) => { - const val = query[op]; - rangeOps[op.replace("$", "")] = - typeof val === "number" ? val : Number(val); - }); - - if (lastPart === "valueSI" || lastPart === "value") { - filters.push({ - term: { - [`${firstPart}.${middlePart}.value_type`]: "number", - }, - }); - } - filters.push({ - range: { [transformedKey]: rangeOps }, - }); - } else { - const operation = Object.keys(query)[0]; - const value = - typeof (query as Record)[operation] === "string" - ? (query as Record)[operation].trim() - : (query as Record)[operation]; - const esOperation = operation.replace("$", ""); - - // NOTE: - // trasnformedKey = "scientificMetadata.someKey.value" - // firstPart = "scientificMetadata", - // middlePart = "someKey" - // lastPart = "value" - const { transformedKey, firstPart, middlePart, lastPart } = - transformMiddleKey(field); - - if (lastPart === "valueSI" || lastPart === "value") { - const numberFilter = { - term: { - [`${firstPart}.${middlePart}.value_type`]: - typeof value === "number" ? "number" : "string", - }, - }; - filters.push(numberFilter); - } - - // NOTE: if value is not a number, we use keyword field for exact match for term queries - // for range queries we can skip this as string values will not be accepted - const targetField = - typeof value !== "number" ? `${field}.keyword` : field; - - const filter = - esOperation === "eq" - ? { - term: { [`${targetField}`]: value }, - } - : { - range: { [`${transformedKey}`]: { [esOperation]: value } }, - }; - - filters.push(filter); - } - } - return filters; -}; - -export const transformFacets = ( - aggregation: AggregationsAggregate, -): Record[] => { - const transformed = Object.entries(aggregation).reduce( - (acc, [key, value]) => { - const isBucketArray = Array.isArray(value.buckets); - - acc[key] = isBucketArray - ? value.buckets.map( - (bucket: AggregationsFrequentItemSetsBucketKeys) => ({ - _id: bucket.key, - count: bucket.doc_count, - }), - ) - : [{ totalSets: value.value }]; - - return acc; - }, - {} as ITransformedFullFacets, - ); - - return [transformed]; -}; diff --git a/src/elastic-search/interfaces/es-common.type.ts b/src/elastic-search/interfaces/es-common.type.ts deleted file mode 100644 index e751ea0ca..000000000 --- a/src/elastic-search/interfaces/es-common.type.ts +++ /dev/null @@ -1,107 +0,0 @@ -export type searchType = - | "text" - | "keyword" - | "long" - | "integer" - | "date" - | "boolean" - | "object" - | "flattened" - | "nested"; - -export type ObjectType = { - begin: string; - end: string; -}; - -export type NumberRangeType = { - min: string; - max: string; -}; - -export interface IShould { - terms?: { - [key: string]: string[] | undefined; - }; - term?: { - [key: string]: string | undefined; - }; - range?: { - [key: string]: { - gte?: string | number; - lte?: string | number; - }; - }; -} - -export interface IBoolShould { - bool: { - should: IShould[]; - minimum_should_match?: number; - }; -} - -export interface IFilter { - terms?: { - [key: string]: string[]; - }; - term?: { - [key: string]: boolean | string; - }; - range?: { - [key: string]: { - gte?: string | number; - lte?: string | number; - }; - }; - match?: { - [key: string]: string | number; - }; - nested?: { - path: string; - query: { - bool: { - must: ( - | { term?: { [key: string]: string } } - | { range?: { [key: string]: { [key: string]: string | number } } } - )[]; - }; - }; - }; - bool?: { - should: IShould[]; - minimum_should_match?: number; - }; -} - -export interface IFullFacets { - [key: string]: { - terms?: { - field: string; - order: { - _key?: string; - _count?: string; - }; - }; - value_count?: { - field: "pid"; - }; - }; -} - -export interface ITransformedFullFacets { - [key: string]: - | { - _id: string; - count: number; - } - | { totalSets: number }; -} - -export interface ScientificQuery { - [key: string]: Record | "$and" | "$or"; -} - -export interface nestedQueryObject { - [key: string]: Record; -} diff --git a/src/elastic-search/interfaces/mappingInterface.type.ts b/src/elastic-search/interfaces/mappingInterface.type.ts deleted file mode 100644 index b4a62b0f3..000000000 --- a/src/elastic-search/interfaces/mappingInterface.type.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { searchType } from "./es-common.type"; - -export interface MappingProperty { - type: searchType; - fields?: { - keyword: { - type: searchType; - ignore_above: number; - }; - }; - [key: string]: unknown; -} - -export interface MappingObject { - [key: string]: MappingProperty; -} diff --git a/src/elastic-search/providers/fields.enum.ts b/src/elastic-search/providers/fields.enum.ts deleted file mode 100644 index 8030407ab..000000000 --- a/src/elastic-search/providers/fields.enum.ts +++ /dev/null @@ -1,38 +0,0 @@ -export enum FilterFields { - Keywords = "keywords", - Pid = "pid", - Type = "type", - CreationLocation = "creationLocation", - CreationTime = "creationTime", - OwnerGroup = "ownerGroup", - AccessGroups = "accessGroups", - ScientificMetadata = "scientific", - IsPublished = "isPublished", - DatasetName = "datasetName", - Mode = "mode", -} - -export enum MustFields { - DatasetName = "datasetName", - Description = "description", -} - -export enum ShouldFields { - SharedWith = "sharedWith", - UserGroups = "userGroups", -} - -export enum FacetFields { - Type = "type", - CreationLocation = "creationLocation", - OwnerGroup = "ownerGroup", - AccessGroups = "accessGroups", - Keywords = "keywords", -} - -export enum SortFields { - DatasetName = "datasetName", - DatasetNameKeyword = "datasetName.keyword", - ScientificMetadata = "scientificMetadata", - ScientificMetadataRunNumberValue = "scientificMetadata.runnumber.value", -} diff --git a/src/elastic-search/providers/query-builder.service.ts b/src/elastic-search/providers/query-builder.service.ts deleted file mode 100644 index 47b83fc86..000000000 --- a/src/elastic-search/providers/query-builder.service.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { Injectable, Logger } from "@nestjs/common"; -import { QueryDslQueryContainer } from "@elastic/elasticsearch/lib/api/types"; -import { IDatasetFields } from "src/datasets/interfaces/dataset-filters.interface"; -import { - IBoolShould, - IFilter, - IFullFacets, - IShould, - NumberRangeType, - ObjectType, - ScientificQuery, -} from "../interfaces/es-common.type"; -import { - FilterFields, - MustFields, - FacetFields, - ShouldFields, -} from "./fields.enum"; - -import { mapScientificQuery } from "src/common/utils"; -import { IScientificFilter } from "src/common/interfaces/common.interface"; -import { convertToElasticSearchQuery } from "../helpers/utils"; - -@Injectable() -export class SearchQueryService { - readonly filterFields = [...Object.values(FilterFields)]; - readonly mustFields = [...Object.values(MustFields)]; - readonly shouldFields = [...Object.values(ShouldFields)]; - readonly facetFields = [...Object.values(FacetFields)]; - readonly textQuerySplitMethod = /[ ,]+/; - - public buildSearchQuery(searchParam: IDatasetFields) { - try { - const { ...fields } = searchParam; - - const filter = this.buildFilterFields(fields); - const should = this.buildShouldFields(fields); - const must = this.buildTextQuery(fields); - - // NOTE: The final query flow is as follows: - // step 1. Build filter fields conditions must match all filter fields - // step 2. Build should fields conditions must match at least one should field - // step 3. Build text query conditions must match all text query fields - return this.constructFinalQuery(filter, should, must); - } catch (err) { - Logger.error("Elastic search build search query failed"); - throw err; - } - } - private buildFilterFields(fields: Partial): IFilter[] { - const filter: IFilter[] = []; - - Object.entries(fields).forEach(([key, value]) => { - if (this.shouldFields.includes(key as ShouldFields) || key === "text") { - return; - } - - const filterQueries = this.buildTermsFilter(key, value); - filter.push(...filterQueries); - }); - - return filter; - } - - private buildShouldFields(fields: Partial) { - const shouldFilter: IShould[] = []; - if (fields["sharedWith"]) { - const termFilter = { terms: { sharedWith: fields["sharedWith"] } }; - - shouldFilter.push(termFilter); - } - - if (fields["userGroups"]) { - const ownerGroup = { terms: { ownerGroup: fields["userGroups"] } }; - const accessGroups = { terms: { accessGroups: fields["userGroups"] } }; - - shouldFilter.push(ownerGroup, accessGroups); - } - return { bool: { should: shouldFilter, minimum_should_match: 1 } }; - } - - private buildTextQuery( - fields: Partial, - ): QueryDslQueryContainer[] { - let wildcardQueries: QueryDslQueryContainer[] = []; - const { text } = fields; - - //NOTE: if text field is present, we query both datasetName and description fields - if (text) { - wildcardQueries = this.buildWildcardQueries(text); - } - - return wildcardQueries.length > 0 - ? [{ bool: { should: wildcardQueries, minimum_should_match: 1 } }] - : []; - } - - private splitSearchText(text: string): string[] { - return text - .toLowerCase() - .trim() - .split(this.textQuerySplitMethod) - .filter(Boolean); - } - - private buildWildcardQueries(text: string): QueryDslQueryContainer[] { - const terms = this.splitSearchText(text); - return terms.flatMap((term) => - this.mustFields.map((fieldName) => ({ - wildcard: { [fieldName]: { value: `*${term}*` } }, - })), - ); - } - - private buildTermsFilter(fieldName: string, values: unknown) { - const filterArray: IFilter[] = []; - - if (Array.isArray(values) && values.length === 0) { - return filterArray; - } - - switch (fieldName) { - case FilterFields.ScientificMetadata: - const scientificFilterQuery = mapScientificQuery( - fieldName, - values as IScientificFilter[], - ); - - const esScientificFilterQuery = convertToElasticSearchQuery( - scientificFilterQuery as ScientificQuery, - ); - filterArray.push({ - nested: { - path: "scientificMetadata", - query: { - bool: { - must: esScientificFilterQuery, - }, - }, - }, - }); - break; - - case FilterFields.CreationTime: - filterArray.push({ - range: { - [fieldName]: { - gte: (values as ObjectType).begin, - lte: (values as ObjectType).end, - }, - }, - }); - break; - - case FilterFields.Pid: - filterArray.push({ - term: { - [fieldName]: values as string, - }, - }); - break; - - case FilterFields.IsPublished: - filterArray.push({ - term: { - [fieldName]: values as boolean, - }, - }); - break; - default: - if (Array.isArray(values)) { - filterArray.push({ - terms: { - [fieldName]: values, - }, - }); - } - if (typeof values === "string" || typeof values === "number") { - filterArray.push({ - match: { - [fieldName]: values as string | number, - }, - }); - } - - if ( - values && - typeof values === "object" && - ("min" in values || - "max" in values || - "begin" in values || - "end" in values) - ) { - filterArray.push({ - range: { - [fieldName]: { - gte: - (values as NumberRangeType).min ?? - (values as ObjectType).begin, - lte: - (values as NumberRangeType).max ?? (values as ObjectType).end, - }, - }, - }); - } - break; - } - return filterArray; - } - - private constructFinalQuery( - filter: IFilter[], - should: IBoolShould, - query: QueryDslQueryContainer[], - ) { - const finalQuery = { - query: { - bool: { - filter: [...filter, should], - must: query, - }, - }, - }; - return finalQuery; - } - - public buildFullFacetPipeline(facetFields = this.facetFields) { - const pipeline: IFullFacets = { - all: { - value_count: { - field: "pid", - }, - }, - }; - - for (const field of facetFields) { - pipeline[field] = { - terms: { - field: field, - order: { - _count: "desc", - }, - }, - }; - } - return pipeline; - } -} diff --git a/src/instruments/instruments.module.ts b/src/instruments/instruments.module.ts index 4a8be983a..ef340cb82 100644 --- a/src/instruments/instruments.module.ts +++ b/src/instruments/instruments.module.ts @@ -10,12 +10,14 @@ import { InstrumentsController } from "./instruments.controller"; import { InstrumentsService } from "./instruments.service"; import { Instrument, InstrumentSchema } from "./schemas/instrument.schema"; import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; +import { MetadataKeysModule } from "src/metadata-keys/metadatakeys.module"; @Module({ controllers: [InstrumentsController], imports: [ CaslModule, ConfigModule, + MetadataKeysModule, MongooseModule.forFeature([ { name: GenericHistory.name, diff --git a/src/instruments/instruments.service.spec.ts b/src/instruments/instruments.service.spec.ts index 78085c396..88621504f 100644 --- a/src/instruments/instruments.service.spec.ts +++ b/src/instruments/instruments.service.spec.ts @@ -3,6 +3,12 @@ import { Test, TestingModule } from "@nestjs/testing"; import { Model } from "mongoose"; import { InstrumentsService } from "./instruments.service"; import { Instrument } from "./schemas/instrument.schema"; +import { MetadataKeysService } from "src/metadata-keys/metadatakeys.service"; + +class MetadataKeysServiceMock { + insertManyFromSource = jest.fn().mockResolvedValue([]); + replaceManyFromSource = jest.fn().mockResolvedValue(undefined); +} const mockInstrument: Instrument = { _id: "testPid", @@ -35,6 +41,7 @@ describe("InstrumentsService", () => { exec: jest.fn(), }, }, + { provide: MetadataKeysService, useClass: MetadataKeysServiceMock }, ], }).compile(); diff --git a/src/instruments/instruments.service.ts b/src/instruments/instruments.service.ts index e0d944067..921927dcc 100644 --- a/src/instruments/instruments.service.ts +++ b/src/instruments/instruments.service.ts @@ -1,6 +1,6 @@ -import { Injectable, Inject, Scope } from "@nestjs/common"; +import { Injectable, Inject, Scope, NotFoundException } from "@nestjs/common"; import { InjectModel } from "@nestjs/mongoose"; -import { FilterQuery, Model } from "mongoose"; +import { FilterQuery, Model, UpdateQuery } from "mongoose"; import { IFilters } from "src/common/interfaces/common.interface"; import { CountApiResponse } from "src/common/types"; import { @@ -14,21 +14,46 @@ import { Instrument, InstrumentDocument } from "./schemas/instrument.schema"; import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; import { REQUEST } from "@nestjs/core"; import { Request } from "express"; +import { + MetadataKeysService, + MetadataSourceDoc, +} from "src/metadata-keys/metadatakeys.service"; @Injectable({ scope: Scope.REQUEST }) export class InstrumentsService { constructor( @InjectModel(Instrument.name) private instrumentModel: Model, + private metadataKeysService: MetadataKeysService, @Inject(REQUEST) private request: Request, ) {} + private createMetadataKeysInstance( + doc: UpdateQuery, + ): MetadataSourceDoc { + const source: MetadataSourceDoc = { + sourceType: "instrument", + sourceId: doc.pid, + ownerGroup: doc.ownerGroup, + accessGroups: doc.accessGroups || [], + isPublished: doc.isPublished || false, + metadata: doc.customMetadata ?? {}, + }; + return source; + } + async create(createInstrumentDto: CreateInstrumentDto): Promise { const username = (this.request.user as JWTUser).username; const createdInstrument = new this.instrumentModel( addCreatedByFields(createInstrumentDto, username), ); - return createdInstrument.save(); + const savedInstrument = await createdInstrument.save(); + + await this.metadataKeysService.insertManyFromSource( + this.createMetadataKeysInstance(savedInstrument), + ); + + return savedInstrument; } async findAll(filter: IFilters): Promise { @@ -71,7 +96,8 @@ export class InstrumentsService { updateInstrumentDto: PartialUpdateInstrumentDto, ): Promise { const username = (this.request.user as JWTUser).username; - return this.instrumentModel + + const updatedInstrument = this.instrumentModel .findOneAndUpdate( filter, { @@ -83,9 +109,35 @@ export class InstrumentsService { { new: true, runValidators: true }, ) .exec(); + + if (!updatedInstrument) { + throw new NotFoundException( + `Instrument not found with filter: ${JSON.stringify(filter)}`, + ); + } + + await this.metadataKeysService.replaceManyFromSource( + this.createMetadataKeysInstance(updatedInstrument), + ); + + return updatedInstrument; } async remove(filter: FilterQuery): Promise { - return this.instrumentModel.findOneAndDelete(filter).exec(); + const deletedInstrument = await this.instrumentModel + .findOneAndDelete(filter) + .exec(); + + if (!deletedInstrument) { + throw new NotFoundException( + `Instrument not found with filter: ${JSON.stringify(filter)}`, + ); + } + + await this.metadataKeysService.deleteMany( + this.createMetadataKeysInstance(deletedInstrument), + ); + + return deletedInstrument; } } diff --git a/src/metadata-keys/dto/create-metadata-key.dto.ts b/src/metadata-keys/dto/create-metadata-key.dto.ts new file mode 100644 index 000000000..4e5ca5b2f --- /dev/null +++ b/src/metadata-keys/dto/create-metadata-key.dto.ts @@ -0,0 +1,22 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsString } from "class-validator"; +import { UpdateMetadataKeyDto } from "./update-metadata-key.dto"; + +export class CreateMetadataKeyDto extends UpdateMetadataKeyDto { + @ApiProperty({ + type: String, + required: true, + description: + "Type of item this key has been extracted from. Allowed values: Datasets, Proposals, Samples, Instruments.", + }) + @IsString() + sourceType: string; + + @ApiProperty({ + type: String, + required: true, + description: "Unique identifier of the source item this key is linked to.", + }) + @IsString() + sourceId: string; +} diff --git a/src/metadata-keys/dto/output-metadata-key.dto.ts b/src/metadata-keys/dto/output-metadata-key.dto.ts new file mode 100644 index 000000000..ad561ddc3 --- /dev/null +++ b/src/metadata-keys/dto/output-metadata-key.dto.ts @@ -0,0 +1,78 @@ +import { ApiProperty, PartialType } from "@nestjs/swagger"; +import { + ArrayNotEmpty, + IsArray, + IsBoolean, + IsOptional, + IsString, +} from "class-validator"; +import { QueryableClass } from "src/common/schemas/queryable.schema"; + +export class OutputMetadataKeyDto extends QueryableClass { + @ApiProperty({ + type: String, + required: true, + description: "Unique identifier of this metadata key.", + }) + @IsString() + declare id: string; + + @ApiProperty({ + type: String, + required: true, + description: "Metadata key.", + }) + @IsString() + key: string; + + @ApiProperty({ + type: String, + required: false, + description: "Human readable name associated with this metadata key.", + }) + @IsOptional() + @IsString() + humanReadableName?: string; + + @ApiProperty({ + type: [String], + required: true, + description: "List of user groups that can access this key.", + }) + @IsArray() + @ArrayNotEmpty() + @IsString({ + each: true, + }) + userGroups: string[]; + + @ApiProperty({ + type: String, + required: true, + description: + "Type of item this key has been extracted from. Allowed values: Datasets, Proposals, Samples, Instruments.", + }) + @IsString() + sourceType: string; + + @ApiProperty({ + type: String, + required: true, + description: "Unique identifier of the source item this key is linked to.", + }) + @IsString() + sourceId: string; + + @ApiProperty({ + type: Boolean, + required: true, + default: false, + description: "Flag is true when data are made publicly available.", + }) + @IsBoolean() + isPublished: boolean; +} + +export class PartialOutputMetadataKeyDto extends PartialType( + OutputMetadataKeyDto, +) {} diff --git a/src/metadata-keys/dto/update-metadata-key.dto.ts b/src/metadata-keys/dto/update-metadata-key.dto.ts new file mode 100644 index 000000000..eddaef17c --- /dev/null +++ b/src/metadata-keys/dto/update-metadata-key.dto.ts @@ -0,0 +1,50 @@ +import { ApiProperty, PartialType } from "@nestjs/swagger"; +import { + IsArray, + IsOptional, + IsString, + ArrayNotEmpty, + IsBoolean, +} from "class-validator"; + +export class UpdateMetadataKeyDto { + @ApiProperty({ + type: String, + required: true, + description: "Metadata key.", + }) + @IsString() + key: string; + + @ApiProperty({ + type: String, + required: false, + description: "Human readable name associated with this metadata key.", + }) + @IsOptional() + @IsString() + humanReadableName?: string; + + @ApiProperty({ + type: [String], + required: true, + description: "List of user groups that can access this key.", + }) + @IsArray() + @ArrayNotEmpty() + @IsString({ each: true }) + userGroups: string[]; + + @ApiProperty({ + type: Boolean, + required: true, + default: false, + description: "Flag is true when data are made publicly available.", + }) + @IsBoolean() + isPublished: boolean; +} + +export class PartialUpdateMetadataKeyDto extends PartialType( + UpdateMetadataKeyDto, +) {} diff --git a/src/metadata-keys/metadatakeys.module.ts b/src/metadata-keys/metadatakeys.module.ts new file mode 100644 index 000000000..4e5b9b8db --- /dev/null +++ b/src/metadata-keys/metadatakeys.module.ts @@ -0,0 +1,58 @@ +import { Module } from "@nestjs/common"; +import { + MetadataKeyClass, + MetadataKeySchema, +} from "./schemas/metadatakey.schema"; +import { MetadataKeysV4Controller } from "./metadatakeys.v4.controller"; +import { MetadataKeysService } from "./metadatakeys.service"; +import { HistoryModule } from "src/history/history.module"; +import { MongooseModule } from "@nestjs/mongoose"; +import { ConfigModule, ConfigService } from "@nestjs/config"; +import { + GenericHistory, + GenericHistorySchema, +} from "src/common/schemas/generic-history.schema"; +import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; +import { CaslModule } from "src/casl/casl.module"; + +@Module({ + imports: [ + CaslModule, + HistoryModule, + MongooseModule.forFeatureAsync([ + { + name: MetadataKeyClass.name, + imports: [ + ConfigModule, + MongooseModule.forFeature([ + { + name: GenericHistory.name, + schema: GenericHistorySchema, + }, + ]), + ], + inject: [ConfigService], + useFactory: (configService: ConfigService) => { + const schema = MetadataKeySchema; + + schema.pre("save", async function (next) { + if (!this._id) { + this._id = this.id; + } + + next(); + }); + + // Apply history plugin once if schema name matches TRACKABLES config + applyHistoryPluginOnce(schema, configService); + + return schema; + }, + }, + ]), + ], + exports: [MetadataKeysService], + controllers: [MetadataKeysV4Controller], + providers: [MetadataKeysService], +}) +export class MetadataKeysModule {} diff --git a/src/metadata-keys/metadatakeys.service.spec.ts b/src/metadata-keys/metadatakeys.service.spec.ts new file mode 100644 index 000000000..152b96727 --- /dev/null +++ b/src/metadata-keys/metadatakeys.service.spec.ts @@ -0,0 +1,141 @@ +import { Logger } from "@nestjs/common"; +import { getModelToken } from "@nestjs/mongoose"; +import { Test, TestingModule } from "@nestjs/testing"; +import { MetadataKeysService, MetadataSourceDoc } from "./metadatakeys.service"; +import { MetadataKeyClass } from "./schemas/metadatakey.schema"; + +class MetadataKeyModelMock { + aggregate = jest.fn().mockReturnValue({ + exec: jest.fn().mockResolvedValue([{ key: "k1" }]), + }); + deleteMany = jest.fn().mockReturnValue({ + exec: jest.fn().mockResolvedValue({ deletedCount: 2 }), + }); + insertMany = jest.fn().mockReturnValue([{ _id: "id1" }]); +} + +describe("MetadataKeysService", () => { + let service: MetadataKeysService; + let model: MetadataKeyModelMock; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + MetadataKeysService, + { + provide: getModelToken(MetadataKeyClass.name), + useClass: MetadataKeyModelMock, + }, + ], + }).compile(); + + service = await module.resolve(MetadataKeysService); + model = module.get( + getModelToken(MetadataKeyClass.name), + ) as unknown as MetadataKeyModelMock; + }); + + it("should be defined", () => { + expect(service).toBeDefined(); + }); + + it("findAll builds aggregation pipeline and executes it", async () => { + const filter = { + where: { sourceType: "dataset" }, + fields: ["key"], + limits: { limit: 10, skip: 0, sort: { createdAt: "asc" } }, + }; + + const accessFilter = { userGroups: { $in: ["ess"] } }; + + const res = await service.findAll(filter, accessFilter); + + expect(model.aggregate).toHaveBeenCalledTimes(1); + + const pipeline = model.aggregate.mock.calls[0][0]; + expect(pipeline[0]).toEqual({ + $match: { $and: [accessFilter, filter.where] }, + }); + + expect(res).toEqual([{ key: "k1" }]); + }); + + it("deleteMany deletes and logs result", async () => { + const logSpy = jest.spyOn(Logger, "log").mockImplementation(); + + const filter = { sourceType: "dataset", sourceId: "sid" }; + const result = await service.deleteMany(filter); + + expect(model.deleteMany).toHaveBeenCalledWith(filter); + expect(result.deletedCount).toBe(2); + expect(logSpy).toHaveBeenCalled(); + }); + + it("insertManyFromSource does nothing when metadata is empty", async () => { + const doc: MetadataSourceDoc = { + sourceId: "sid", + sourceType: "dataset", + ownerGroup: "ess", + accessGroups: ["ess"], + isPublished: false, + metadata: {}, + }; + + const res = await service.insertManyFromSource(doc); + + expect(res).toBeUndefined(); + expect(model.insertMany).not.toHaveBeenCalled(); + }); + + it("insertManyFromSource creates metadata keys", async () => { + const doc: MetadataSourceDoc = { + sourceId: "sid", + sourceType: "dataset", + ownerGroup: "ess", + accessGroups: ["swap", "ess"], + isPublished: false, + metadata: { + key1: { human_name: "Key One" }, + key2: {}, + }, + }; + + const res = await service.insertManyFromSource(doc); + + expect(model.insertMany).toHaveBeenCalledTimes(1); + + const insertedDocs = model.insertMany.mock.calls[0][0]; + expect(insertedDocs).toHaveLength(2); + + expect(insertedDocs[0]).toMatchObject({ + key: "key1", + humanReadableName: "Key One", + sourceType: "dataset", + sourceId: "sid", + }); + + expect(res).toEqual([{ _id: "id1" }]); + }); + + it("replaceManyFromSource deletes then inserts", async () => { + const doc: MetadataSourceDoc = { + sourceId: "sid", + sourceType: "dataset", + ownerGroup: "ess", + accessGroups: ["swap"], + isPublished: false, + metadata: { key1: {} }, + }; + + const deleteSpy = jest.spyOn(service, "deleteMany"); + const insertSpy = jest.spyOn(service, "insertManyFromSource"); + + await service.replaceManyFromSource(doc); + + expect(deleteSpy).toHaveBeenCalledWith({ + sourceId: "sid", + sourceType: "dataset", + }); + expect(insertSpy).toHaveBeenCalledWith(doc); + }); +}); diff --git a/src/metadata-keys/metadatakeys.service.ts b/src/metadata-keys/metadatakeys.service.ts new file mode 100644 index 000000000..fc1b06076 --- /dev/null +++ b/src/metadata-keys/metadatakeys.service.ts @@ -0,0 +1,137 @@ +import { Injectable, Logger, Scope } from "@nestjs/common"; +import { InjectModel } from "@nestjs/mongoose"; +import { + MetadataKeyClass, + MetadataKeyDocument, +} from "./schemas/metadatakey.schema"; +import { + DeleteResult, + FilterQuery, + HydratedDocument, + Model, + PipelineStage, + QueryOptions, +} from "mongoose"; +import { isEmpty } from "lodash"; +import { + addCreatedByFields, + parsePipelineProjection, + parsePipelineSort, +} from "src/common/utils"; + +type ScientificMetadataEntry = { + human_name?: string; +}; + +export type MetadataSourceDoc = { + sourceId: string; + sourceType: string; + ownerGroup: string; + accessGroups: string[]; + isPublished: boolean; + metadata: Record; +}; + +@Injectable({ scope: Scope.REQUEST }) +export class MetadataKeysService { + constructor( + @InjectModel(MetadataKeyClass.name) + private metadataKeyModel: Model, + ) {} + + async findAll( + filter: FilterQuery, + accessFilter: FilterQuery, + ): Promise { + const whereFilter: FilterQuery = filter.where ?? {}; + const fieldsProjection: string[] = filter.fields ?? {}; + const limits: QueryOptions = filter.limits ?? { + limit: 100, + skip: 0, + sort: { createdAt: "desc" }, + }; + + const pipeline: PipelineStage[] = [ + { + $match: { + $and: [accessFilter, whereFilter], + }, + }, + ]; + if (!isEmpty(fieldsProjection)) { + const projection = parsePipelineProjection(fieldsProjection); + pipeline.push({ $project: projection }); + } + + if (!isEmpty(limits.sort)) { + const sort = parsePipelineSort(limits.sort); + pipeline.push({ $sort: sort }); + } + + pipeline.push({ $skip: limits.skip || 0 }); + + pipeline.push({ $limit: limits.limit || 100 }); + + const data = await this.metadataKeyModel + .aggregate(pipeline) + .exec(); + + return data; + } + + async deleteMany( + filter: FilterQuery, + ): Promise { + const result = await this.metadataKeyModel.deleteMany(filter).exec(); + + Logger.log( + `MetadataKeys deleted: ${result.deletedCount ?? 0} With filter:`, + { filter }, + ); + + return result; + } + + async insertManyFromSource( + doc: MetadataSourceDoc, + ): Promise[] | void> { + if (isEmpty(doc.metadata)) { + return; + } + const userGroups = Array.from( + new Set([doc.ownerGroup, ...(doc.accessGroups ?? [])].filter(Boolean)), + ) as string[]; + + const isPublished = doc.isPublished; + + const metadata = doc.metadata ?? {}; + + const docs = Object.entries(metadata).map(([key, entry]) => { + const createMetadataKeyDto = { + _id: `${doc.sourceType}_${doc.sourceId}_${key}`, + id: `${doc.sourceType}_${doc.sourceId}_${key}`, + sourceType: doc.sourceType, + sourceId: doc.sourceId, + key, + userGroups, + isPublished, + humanReadableName: (entry as ScientificMetadataEntry).human_name ?? "", + }; + return addCreatedByFields(createMetadataKeyDto, "system"); + }); + + Logger.log( + `Created ${docs.length} MetadataKeys from source ${doc.sourceType} with ID ${doc.sourceId}`, + ); + + return await this.metadataKeyModel.insertMany(docs); + } + + async replaceManyFromSource(doc: MetadataSourceDoc): Promise { + await this.deleteMany({ + sourceId: doc.sourceId, + sourceType: doc.sourceType, + }); + await this.insertManyFromSource(doc); + } +} diff --git a/src/metadata-keys/metadatakeys.v4.controller.spec.ts b/src/metadata-keys/metadatakeys.v4.controller.spec.ts new file mode 100644 index 000000000..761b07ba1 --- /dev/null +++ b/src/metadata-keys/metadatakeys.v4.controller.spec.ts @@ -0,0 +1,125 @@ +// metadatakeys.v4.controller.spec.ts +import { Test, TestingModule } from "@nestjs/testing"; +import { Request } from "express"; +import { accessibleBy } from "@casl/mongoose"; + +import { MetadataKeysV4Controller } from "./metadatakeys.v4.controller"; +import { MetadataKeysService } from "./metadatakeys.service"; +import { CaslAbilityFactory } from "src/casl/casl-ability.factory"; +import { Action } from "src/casl/action.enum"; +import { MetadataKeyClass } from "./schemas/metadatakey.schema"; +import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; + +jest.mock("@casl/mongoose", () => ({ + accessibleBy: jest.fn(), +})); + +class CaslAbilityFactoryMock { + metadataKeyInstanceAccess = jest.fn(); +} + +class MetadataKeysServiceMock { + findAll = jest.fn(); +} + +describe("MetadataKeysV4Controller", () => { + let controller: MetadataKeysV4Controller; + let metadatakeysService: MetadataKeysServiceMock; + let caslAbilityFactory: CaslAbilityFactoryMock; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [MetadataKeysV4Controller], + providers: [ + { provide: MetadataKeysService, useClass: MetadataKeysServiceMock }, + { provide: CaslAbilityFactory, useClass: CaslAbilityFactoryMock }, + ], + }).compile(); + + controller = module.get(MetadataKeysV4Controller); + metadatakeysService = module.get(MetadataKeysService); + caslAbilityFactory = module.get(CaslAbilityFactory); + }); + + it("should be defined", () => { + expect(controller).toBeDefined(); + }); + + it("findAll parses filter, builds accessFilter, and calls service.findAll with parsed filter and accessFilter", async () => { + const request = { user: { username: "u1" } } as unknown as Request; + const user = request.user as JWTUser; + const filterString = `{ + "where": { "sourceId": "testId", "sourceType": "dataset" }, + "limits": { + "limit": 10, + "skip": 0, + "sort": { + "createdAt": "asc" + } + } + }`; + const parsedFilter = JSON.parse(filterString); + + const abilities = {}; + caslAbilityFactory.metadataKeyInstanceAccess.mockReturnValue(abilities); + + const accessFilter = { isPublished: true }; + + const ofType = jest.fn().mockReturnValue(accessFilter); + + const accessibleByReturn = { + ofType, + }; + (accessibleBy as unknown as jest.Mock).mockReturnValue(accessibleByReturn); + + const expected = [{ key: "k1", humanReadableName: "Test K1" }] as unknown[]; + metadatakeysService.findAll.mockResolvedValue(expected); + + const result = await controller.findAll(request, filterString); + + expect(caslAbilityFactory.metadataKeyInstanceAccess).toHaveBeenCalledWith( + user, + ); + + expect(accessibleBy).toHaveBeenCalledWith( + abilities, + Action.MetadataKeysReadInstance, + ); + expect(ofType).toHaveBeenCalledWith(MetadataKeyClass); + + expect(metadatakeysService.findAll).toHaveBeenCalledWith( + parsedFilter, + accessFilter, + ); + + expect(result).toEqual(expected); + }); + + it('findAll uses "{}" when filter is missing', async () => { + const request = { user: { username: "u1" } } as unknown as Request; + + const abilities = {}; + caslAbilityFactory.metadataKeyInstanceAccess.mockReturnValue(abilities); + + const accessFilter = { isPublished: true }; + const accessibleByReturn = { + ofType: () => accessFilter, + }; + (accessibleBy as unknown as jest.Mock).mockReturnValue(accessibleByReturn); + + const expected: unknown[] = []; + metadatakeysService.findAll.mockResolvedValue(expected); + + const result = await controller.findAll( + request, + undefined as unknown as string, + ); + + expect(metadatakeysService.findAll).toHaveBeenCalledWith({}, accessFilter); + expect(result).toEqual(expected); + }); +}); diff --git a/src/metadata-keys/metadatakeys.v4.controller.ts b/src/metadata-keys/metadatakeys.v4.controller.ts new file mode 100644 index 000000000..5b6b299a4 --- /dev/null +++ b/src/metadata-keys/metadatakeys.v4.controller.ts @@ -0,0 +1,89 @@ +import { + Controller, + Get, + HttpStatus, + Req, + Query, + UseGuards, +} from "@nestjs/common"; +import { + ApiBearerAuth, + ApiOperation, + ApiQuery, + ApiResponse, + ApiTags, +} from "@nestjs/swagger"; +import { AppAbility, CaslAbilityFactory } from "src/casl/casl-ability.factory"; +import { MetadataKeysService } from "./metadatakeys.service"; +import { PoliciesGuard } from "src/casl/guards/policies.guard"; +import { OutputMetadataKeyDto } from "./dto/output-metadata-key.dto"; + +import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; +import { Request } from "express"; +import { getSwaggerMetadatakeysFilterContent } from "./types/metadatakeys-filter-content"; +import { MetadataKeyClass } from "./schemas/metadatakey.schema"; +import { Action } from "src/casl/action.enum"; +import { CheckPolicies } from "src/casl/decorators/check-policies.decorator"; +import { FilterValidationPipe } from "src/common/pipes/filter-validation.pipe"; +import { + ALLOWED_METADATAKEYS_FILTER_KEYS, + ALLOWED_METADATAKEYS_KEYS, +} from "./types/metadatakeys-lookup"; +import { accessibleBy } from "@casl/mongoose"; + +@ApiBearerAuth() +@ApiTags("metadata keys v4") +@Controller({ path: "metadatakeys", version: "4" }) +export class MetadataKeysV4Controller { + constructor( + private metadatakeysService: MetadataKeysService, + private caslAbilityFactory: CaslAbilityFactory, + ) {} + + @UseGuards(PoliciesGuard) + @CheckPolicies("metadataKeys", (ability: AppAbility) => + ability.can(Action.MetadataKeysReadEndpoint, MetadataKeyClass), + ) + @Get() + @ApiOperation({ summary: "List metadata keys by text query" }) + @ApiQuery({ + name: "filter", + description: "Database filters to apply when retrieving metadata keys", + required: false, + type: String, + content: getSwaggerMetadatakeysFilterContent(), + }) + @ApiResponse({ + status: HttpStatus.OK, + type: OutputMetadataKeyDto, + isArray: true, + description: "Return the metadata keys requested", + }) + async findAll( + @Req() request: Request, + @Query( + "filter", + new FilterValidationPipe( + ALLOWED_METADATAKEYS_KEYS, + ALLOWED_METADATAKEYS_FILTER_KEYS, + { + where: true, + include: false, + fields: true, + limits: true, + }, + ), + ) + filter: string, + ) { + const user: JWTUser = request.user as JWTUser; + const parsedFilter = JSON.parse(filter ?? "{}"); + const abilities = this.caslAbilityFactory.metadataKeyInstanceAccess(user); + const accessFilter = accessibleBy( + abilities, + Action.MetadataKeysReadInstance, + ).ofType(MetadataKeyClass); + + return this.metadatakeysService.findAll(parsedFilter, accessFilter); + } +} diff --git a/src/metadata-keys/schemas/metadatakey.schema.ts b/src/metadata-keys/schemas/metadatakey.schema.ts new file mode 100644 index 000000000..b4c6b6d39 --- /dev/null +++ b/src/metadata-keys/schemas/metadatakey.schema.ts @@ -0,0 +1,103 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import { ApiProperty } from "@nestjs/swagger"; +import { Document } from "mongoose"; +import { QueryableClass } from "src/common/schemas/queryable.schema"; +import { v4 as uuidv4 } from "uuid"; + +export type MetadataKeyDocument = MetadataKeyClass & Document; + +@Schema({ + collection: "MetadataKeys", + minimize: false, + timestamps: true, + toJSON: { + getters: true, + }, +}) +export class MetadataKeyClass extends QueryableClass { + @ApiProperty({ type: String, default: () => uuidv4() }) + @Prop({ + type: String, + default: () => uuidv4(), + sparse: true, + }) + id: string; + + @Prop({ + type: String, + }) + _id: string; + + @ApiProperty({ + type: String, + required: true, + description: "Metadata key.", + }) + @Prop({ + type: String, + required: true, + index: true, + }) + key: string; + + @ApiProperty({ + type: String, + required: false, + description: "Human readable name associated with the metadata key.", + }) + @Prop({ + type: String, + required: false, + }) + humanReadableName?: string; + + @ApiProperty({ + type: [String], + required: true, + description: "List of user groups that can access this key.", + }) + @Prop({ + type: [String], + required: true, + }) + userGroups: string[]; + + @ApiProperty({ + type: String, + required: true, + description: + "Type of item this key has been extracted from. Allowed values: Datasets, Proposals, Samples, Instruments.", + }) + @Prop({ + type: String, + required: true, + index: true, + }) + sourceType: string; + + @ApiProperty({ + type: String, + required: true, + description: "Unique identifier of the source item this key is linked to.", + }) + @Prop({ + type: String, + required: true, + index: true, + }) + sourceId: string; + + @ApiProperty({ + type: Boolean, + required: true, + description: "Flag is true when data are made publicly available.", + }) + @Prop({ type: Boolean, required: true }) + isPublished: boolean; +} + +export const MetadataKeySchema = SchemaFactory.createForClass(MetadataKeyClass); + +MetadataKeySchema.index({ sourceType: 1, sourceId: 1 }); +MetadataKeySchema.index({ sourceType: 1, userGroups: 1, key: 1 }); +MetadataKeySchema.index({ sourceType: 1, userGroups: 1, humanReadableName: 1 }); diff --git a/src/metadata-keys/types/metadatakeys-filter-content.ts b/src/metadata-keys/types/metadatakeys-filter-content.ts new file mode 100644 index 000000000..b7a38afab --- /dev/null +++ b/src/metadata-keys/types/metadatakeys-filter-content.ts @@ -0,0 +1,83 @@ +import { + ContentObject, + SchemaObject, +} from "@nestjs/swagger/dist/interfaces/open-api-spec.interface"; +import { boolean } from "mathjs"; + +const FILTERS: Record<"limits" | "fields" | "where" | "include", object> = { + where: { + type: "object", + example: { + sourceType: "dataset", + sourceId: "datasetId", + key: "metadata_key_name", + }, + }, + include: {}, + fields: { + type: "array", + items: { + type: "string", + example: "key", + }, + }, + limits: { + type: "object", + properties: { + limit: { + type: "number", + example: 10, + }, + skip: { + type: "number", + example: 0, + }, + sort: { + type: "object", + properties: { + createdAt: { + type: "string", + example: "asc | desc", + }, + }, + }, + }, + }, +}; + +/** + * NOTE: This is disabled only for the official sdk package generation as the schema validation complains about the content field. + * But we want to have it when we run the application as it improves swagger documentation and usage a lot. + * We use "content" property as it is described in the swagger specification: https://swagger.io/docs/specification/v3_0/describing-parameters/#schema-vs-content:~:text=explode%3A%20false-,content,-is%20used%20in + */ +export const getSwaggerMetadatakeysFilterContent = ( + filtersToInclude: Record = { + where: true, + include: false, + fields: true, + limits: true, + }, +): ContentObject | undefined => { + if (boolean(process.env.SDK_PACKAGE_SWAGGER_HELPERS_DISABLED ?? false)) { + return undefined; + } + + const filterContent: Record = { + "application/json": { + schema: { + type: "object", + properties: {}, + }, + }, + }; + + for (const filtersKey in filtersToInclude) { + const key = filtersKey as keyof typeof FILTERS; + + if (filtersToInclude[key] && FILTERS[key]) { + filterContent["application/json"].schema.properties![key] = FILTERS[key]; + } + } + + return filterContent; +}; diff --git a/src/metadata-keys/types/metadatakeys-lookup.ts b/src/metadata-keys/types/metadatakeys-lookup.ts new file mode 100644 index 000000000..5698a80f7 --- /dev/null +++ b/src/metadata-keys/types/metadatakeys-lookup.ts @@ -0,0 +1,41 @@ +import { PipelineStage } from "mongoose"; +import { OutputMetadataKeyDto } from "../dto/output-metadata-key.dto"; + +export enum MetadataKeysLookupKeysEnum {} + +export const METADATA_KEYS_LOOKUP_FIELDS: Record< + MetadataKeysLookupKeysEnum, + PipelineStage.Lookup | undefined +> = {}; + +// Metadata keys specific keys that are allowed +export const ALLOWED_METADATAKEYS_KEYS = [ + ...Object.keys(new OutputMetadataKeyDto()), +]; + +// Allowed keys taken from mongoose QuerySelector. +export const ALLOWED_METADATAKEYS_FILTER_KEYS: Record = { + where: [ + "where", + "$in", + "$or", + "$and", + "$nor", + "$match", + "$eq", + "$gt", + "$gte", + "$lt", + "$lte", + "$ne", + "$nin", + "$not", + "$exists", + "$regex", + "$options", + "$elemMatch", + ], + include: [], + limits: ["limits", "limit", "skip", "sort"], + fields: ["fields"], +}; diff --git a/src/opensearch/dto/create-index.dto.ts b/src/opensearch/dto/create-index.dto.ts new file mode 100644 index 000000000..2812b90c5 --- /dev/null +++ b/src/opensearch/dto/create-index.dto.ts @@ -0,0 +1,20 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsObject, IsOptional } from "class-validator"; +import { UpdateIndexDto } from "./update-index.dto"; +import type { TypeMapping } from "@opensearch-project/opensearch/api/_types/_common.mapping"; + +export class CreateIndexDto extends UpdateIndexDto { + @ApiProperty({ + description: "Index mappings", + type: Object, + example: { + properties: { + datasetName: { type: "text" }, + ownerGroup: { type: "keyword" }, + }, + }, + }) + @IsObject() + @IsOptional() + mappings: TypeMapping; +} diff --git a/src/opensearch/dto/dataset-opensearch.dto.ts b/src/opensearch/dto/dataset-opensearch.dto.ts new file mode 100644 index 000000000..d86f668a2 --- /dev/null +++ b/src/opensearch/dto/dataset-opensearch.dto.ts @@ -0,0 +1,17 @@ +import { PickType } from "@nestjs/swagger"; +import { Expose } from "class-transformer"; +import { OutputDatasetDto } from "src/datasets/dto/output-dataset.dto"; + +import { DATASET_OPENSEARCH_FIELDS } from "src/opensearch/utils/dataset-opensearch.utils"; + +export class DatasetOpenSearchDto extends PickType( + OutputDatasetDto, + DATASET_OPENSEARCH_FIELDS, +) { + @Expose() pid: string; + @Expose() description?: string; + @Expose() datasetName: string; + @Expose() isPublished?: boolean; + @Expose() ownerGroup: string; + @Expose() accessGroups: string[]; +} diff --git a/src/opensearch/dto/update-index.dto.ts b/src/opensearch/dto/update-index.dto.ts new file mode 100644 index 000000000..0d278a0e8 --- /dev/null +++ b/src/opensearch/dto/update-index.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from "@nestjs/swagger"; +import type { IndexSettings } from "@opensearch-project/opensearch/api/_types/indices._common"; +import { IsObject, IsOptional, IsString } from "class-validator"; + +export class UpdateIndexDto { + @ApiProperty({ + type: String, + required: true, + default: "dataset", + description: "Update an index with this name", + }) + @IsString() + @IsOptional() + index: string; + + @ApiProperty({ + description: "Index settings to update", + type: Object, + example: { + index: { + number_of_replicas: 1, + refresh_interval: "1s", + max_result_window: 1000000, + }, + }, + }) + @IsObject() + @IsOptional() + settings: IndexSettings; +} diff --git a/src/opensearch/interfaces/os-common.type.ts b/src/opensearch/interfaces/os-common.type.ts new file mode 100644 index 000000000..2420e3d77 --- /dev/null +++ b/src/opensearch/interfaces/os-common.type.ts @@ -0,0 +1,5 @@ +export interface ISearchFilter { + userGroups?: string[]; + isPublished?: boolean; + text?: string; +} diff --git a/src/opensearch/opensearch.controller.ts b/src/opensearch/opensearch.controller.ts new file mode 100644 index 000000000..d451486a4 --- /dev/null +++ b/src/opensearch/opensearch.controller.ts @@ -0,0 +1,196 @@ +import { + Controller, + HttpCode, + HttpStatus, + Post, + Get, + Query, + UseInterceptors, + UseGuards, + Body, +} from "@nestjs/common"; +import { + ApiTags, + ApiBearerAuth, + ApiResponse, + ApiQuery, + ApiBody, + ApiOperation, +} from "@nestjs/swagger"; +import { Action } from "src/casl/action.enum"; +import { AppAbility } from "src/casl/casl-ability.factory"; +import { CheckPolicies } from "src/casl/decorators/check-policies.decorator"; +import { PoliciesGuard } from "src/casl/guards/policies.guard"; +import { DatasetsService } from "src/datasets/datasets.service"; +import { SubDatasetsPublicInterceptor } from "src/datasets/interceptors/datasets-public.interceptor"; +import { CreateIndexDto } from "./dto/create-index.dto"; + +import { UpdateIndexDto } from "./dto/update-index.dto"; +import { OpensearchService } from "./opensearch.service"; +import { Opensearch } from "./opensearch.subject"; + +@ApiBearerAuth() +@ApiTags("opensearch") +@Controller("opensearch") +export class OpensearchController { + constructor( + private readonly opensearchService: OpensearchService, + private readonly datasetService: DatasetsService, + ) {} + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @HttpCode(HttpStatus.CREATED) + @ApiBody({ + description: `If settings and mappings are not provided, + they will be loaded from the opensearchConfig.json file. + To use the default config, simply omit settings and mappings from the request body.`, + type: CreateIndexDto, + }) + @ApiResponse({ + status: HttpStatus.CREATED, + description: "Create index", + }) + @Post("/create-index") + async createIndex(@Body() createIndexDto: CreateIndexDto) { + return this.opensearchService.createIndex(createIndexDto); + } + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @ApiOperation({ + summary: "Sync data from MongoDB to OpenSearch", + description: `Syncs the dataset collection to the specified OpenSearch index. + Defaults to the index configured in OPENSEARCH_DEFAULT_INDEX. + Currently only supports the dataset collection.`, + }) + @ApiQuery({ + name: "index", + description: "The OpenSearch index name to sync the data into", + default: "dataset", + type: String, + }) + @HttpCode(HttpStatus.OK) + @ApiResponse({ + status: 200, + description: "Successfully synced data from MongoDB to OpenSearch", + }) + @Post("/sync-database") + async syncDatabase(@Query("index") index: string) { + const esIndex = index.trim(); + // NOTE: for now, we will only sync datasets to opensearch, + // but this can be easily extended to other data in the future if needed + return await this.datasetService.syncDatasetsToOpensearch(esIndex); + } + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @HttpCode(HttpStatus.OK) + @UseInterceptors(SubDatasetsPublicInterceptor) + @ApiQuery({ + name: "textQuery", + description: "Partial search text for datasetName and description fields", + type: String, + }) + @ApiQuery({ + name: "index", + description: "The index name to search", + default: "dataset", + required: false, + type: String, + }) + @ApiQuery({ + name: "limit", + description: "The maximum number of results to return", + required: false, + type: Number, + }) + @ApiQuery({ + name: "skip", + description: "The number of results to skip", + required: false, + type: Number, + }) + @ApiResponse({ + status: 200, + description: + "Successfully retrieved search results in _ids from Opensearch.", + }) + @Post("/search") + async fetchOSResults( + @Query("index") index: string, + @Query("limit") limit: number, + @Query("skip") skip: number, + @Query("textQuery") text: string, + ) { + return this.opensearchService.search({ text }, index, limit, skip); + } + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @HttpCode(HttpStatus.OK) + @ApiQuery({ + name: "index", + description: "The index name to delete", + default: "dataset", + type: String, + }) + @ApiResponse({ + status: 200, + description: "Delete index", + }) + @Post("/delete-index") + async deleteIndex(@Query("index") index: string) { + return this.opensearchService.deleteIndex(index.trim()); + } + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @HttpCode(HttpStatus.OK) + @ApiQuery({ + name: "index", + description: "The index name to get the config for", + default: "dataset", + type: String, + }) + @ApiResponse({ + status: 200, + description: "Get index config including settings and mappings", + }) + @Get("/get-index") + async getIndex(@Query("index") index: string) { + return this.opensearchService.getIndexConfig(index.trim()); + } + + @UseGuards(PoliciesGuard) + @CheckPolicies("opensearch", (ability: AppAbility) => + ability.can(Action.Manage, Opensearch), + ) + @HttpCode(HttpStatus.OK) + @ApiBody({ + description: ` + If settings are not provided, + they will be loaded from the opensearchConfig.json file. + To use the default config, simply omit settings from the request body. + for more details: https://docs.opensearch.org/latest/install-and-configure/configuring-opensearch/index-settings/`, + type: UpdateIndexDto, + }) + @ApiResponse({ + status: 200, + description: "Successfully updated index settings", + }) + @Post("/update-index") + async updateIndex(@Body() updateIndexDto: UpdateIndexDto) { + return this.opensearchService.updateIndexSettings(updateIndexDto); + } +} diff --git a/src/elastic-search/elastic-search.module.ts b/src/opensearch/opensearch.module.ts similarity index 52% rename from src/elastic-search/elastic-search.module.ts rename to src/opensearch/opensearch.module.ts index b3e774ada..21497f941 100644 --- a/src/elastic-search/elastic-search.module.ts +++ b/src/opensearch/opensearch.module.ts @@ -2,14 +2,15 @@ import { Module, forwardRef } from "@nestjs/common"; import { CaslModule } from "src/casl/casl.module"; import { ConfigModule } from "@nestjs/config"; import { DatasetsModule } from "src/datasets/datasets.module"; -import { ElasticSearchServiceController } from "./elastic-search.controller"; -import { ElasticSearchService } from "./elastic-search.service"; + import { SearchQueryService } from "./providers/query-builder.service"; +import { OpensearchService } from "./opensearch.service"; +import { OpensearchController } from "./opensearch.controller"; @Module({ imports: [forwardRef(() => DatasetsModule), ConfigModule, CaslModule], - controllers: [ElasticSearchServiceController], - providers: [ElasticSearchService, SearchQueryService], - exports: [ElasticSearchService, SearchQueryService], + controllers: [OpensearchController], + providers: [OpensearchService, SearchQueryService], + exports: [OpensearchService, SearchQueryService], }) -export class ElasticSearchModule {} +export class OpensearchModule {} diff --git a/src/elastic-search/elastic-search.service.spec.ts b/src/opensearch/opensearch.service.spec.ts similarity index 62% rename from src/elastic-search/elastic-search.service.spec.ts rename to src/opensearch/opensearch.service.spec.ts index b86762852..0f327b5b7 100644 --- a/src/elastic-search/elastic-search.service.spec.ts +++ b/src/opensearch/opensearch.service.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from "@nestjs/testing"; import { ConfigService } from "@nestjs/config"; -import { ElasticSearchService } from "./elastic-search.service"; +import { OpensearchService } from "./opensearch.service"; import { SearchQueryService } from "./providers/query-builder.service"; import { DatasetsService } from "src/datasets/datasets.service"; @@ -8,23 +8,23 @@ import { DatasetsService } from "src/datasets/datasets.service"; class SearchQueryServiceMock {} class DatasetsServiceMock {} -describe("ElasticSearchService", () => { - let service: ElasticSearchService; +describe("OpensearchService", () => { + let service: OpensearchService; const mockConfigService = { get: () => ({ - "elasticSearch.host": "fake", - "elasticSearch.username": "fake", - "elasticSearch.password": "fake", - "elasticSearch.enabled": "yes", - "elasticSearch.defaultIndex": "fake", + "opensearch.host": "fake", + "opensearch.username": "fake", + "opensearch.password": "fake", + "opensearch.enabled": "yes", + "opensearch.defaultIndex": "fake", }), }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ - ElasticSearchService, + OpensearchService, { provide: ConfigService, useValue: mockConfigService, @@ -37,10 +37,10 @@ describe("ElasticSearchService", () => { ], }).compile(); - service = module.get(ElasticSearchService); + service = module.get(OpensearchService); }); - it("should properly load ElasticSearchService", () => { + it("should properly load OpensearchService", () => { expect(service).toBeDefined(); }); }); diff --git a/src/opensearch/opensearch.service.ts b/src/opensearch/opensearch.service.ts new file mode 100644 index 000000000..d2dd82e9f --- /dev/null +++ b/src/opensearch/opensearch.service.ts @@ -0,0 +1,386 @@ +import { + HttpException, + HttpStatus, + Injectable, + Logger, + OnModuleInit, +} from "@nestjs/common"; +import { Client } from "@opensearch-project/opensearch"; + +import { SearchQueryService } from "./providers/query-builder.service"; + +import { + DatasetClass, + DatasetDocument, +} from "src/datasets/schemas/dataset.schema"; +import { ConfigService } from "@nestjs/config"; +import { sleep } from "src/common/utils"; + +import type { IndexSettings } from "@opensearch-project/opensearch/api/_types/indices._common"; +import { ISearchFilter } from "./interfaces/os-common.type"; +import { CreateIndexDto } from "./dto/create-index.dto"; +import { UpdateIndexDto } from "./dto/update-index.dto"; +import type { TypeMapping } from "@opensearch-project/opensearch/api/_types/_common.mapping"; + +@Injectable() +export class OpensearchService implements OnModuleInit { + private osClient: Client; + private host: string; + private username: string; + private password: string; + private refresh: "false" | "wait_for"; + private osConfigs: { + settings: IndexSettings; + mappings: TypeMapping; + } | null; + + public defaultIndex: string; + + constructor( + private readonly searchService: SearchQueryService, + private readonly configService: ConfigService, + ) { + this.host = this.configService.get("opensearch.host") || ""; + this.username = this.configService.get("opensearch.username") || ""; + this.password = this.configService.get("opensearch.password") || ""; + + this.refresh = + this.configService.get<"false" | "wait_for">("opensearch.refresh") || + "false"; + + this.defaultIndex = + this.configService.get("opensearch.defaultIndex") || "dataset"; + + this.osConfigs = + this.configService.get<{ + settings: IndexSettings; + mappings: TypeMapping; + }>("opensearchConfig") || null; + + if (!this.host || !this.username || !this.password || !this.defaultIndex) { + Logger.warn( + `Missing Opensearch configuration for host: ${this.host}, username: ${this.username}, + password: ${this.password} or defaultIndex: ${this.defaultIndex}`, + "Opensearch", + ); + } + if (!this.osConfigs) { + Logger.warn( + `Missing Opensearch index configuration, using default settings and mappings`, + "Opensearch", + ); + } + } + + onModuleInit() { + this.initWithRetry(); + } + + private async connect() { + const connection = new Client({ + node: this.host, + auth: { + username: this.username, + password: this.password, + }, + ssl: { + rejectUnauthorized: false, + }, + }); + + await connection.ping(); + + this.osClient = connection; + } + private async initWithRetry( + maxRetries = 10, + initialDelayMs = 5000, + maxDelayMs = 60000, + ) { + let delayMs = initialDelayMs; + let retryCount = 0; + + while (retryCount < maxRetries) { + try { + await this.connect(); + + const isIndexExists = await this.isIndexExists(this.defaultIndex); + if (!isIndexExists) { + await this.createIndex({ + index: this.defaultIndex, + settings: this.osConfigs?.settings || {}, + mappings: this.osConfigs?.mappings || {}, + }); + Logger.log(`New index ${this.defaultIndex} is created`, "Opensearch"); + } + + Logger.log("Opensearch Connected", "Opensearch"); + return; + } catch (error) { + retryCount++; + Logger.warn( + `Opensearch connection failed (attempt ${retryCount}/${maxRetries}), retrying in ${delayMs / 1000}s...`, + error, + ); + await sleep(delayMs); + delayMs = Math.min(delayMs * 2, maxDelayMs); + } + } + + Logger.error( + `Opensearch failed to connect after ${maxRetries} attempts, running without it`, + "Opensearch", + ); + } + + connected() { + return !!this.osClient; + } + + async isIndexExists(index = this.defaultIndex) { + const { body: indexExists } = await this.osClient.indices.exists({ index }); + return indexExists; + } + + async isPopulated(index = this.defaultIndex) { + const { body } = await this.getCount(index); + + if (body.count > 0) { + return true; + } + Logger.error( + `Opensearch is enabled but index ${index} is empty`, + "Opensearch", + ); + + return false; + } + + async createIndex(createIndexDto: CreateIndexDto) { + const index = createIndexDto.index.trim(); + const { settings, mappings } = createIndexDto; + + try { + const newIndex = await this.osClient.indices.create({ + index, + body: { + settings: settings || this.osConfigs?.settings, + mappings: mappings || this.osConfigs?.mappings, + }, + }); + Logger.log(`Opensearch Index Created-> Index: ${index}`, "Opensearch"); + + return newIndex; + } catch (error) { + throw new HttpException( + `createIndex failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + async syncDatabase(collection: DatasetClass[], index = this.defaultIndex) { + const indexExists = await this.osClient.indices.exists({ index }); + if (!indexExists) { + throw new Error("Index not found"); + } + + const bulkResponse = await this.performBulkOperation(collection, index); + + Logger.log( + JSON.stringify(bulkResponse, null, 0), + "Opensearch Data Synchronization Response", + ); + + return bulkResponse; + } + + async getCount(index = this.defaultIndex) { + try { + return await this.osClient.count({ index }); + } catch (error) { + throw new HttpException( + `getCount failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async updateIndexSettings(updateIndexDto: UpdateIndexDto) { + const index = updateIndexDto.index.trim(); + + try { + await this.osClient.indices.close({ + index, + }); + await this.osClient.indices.putSettings({ + index, + body: { settings: updateIndexDto.settings || this.osConfigs?.settings }, + }); + + await this.osClient.indices.open({ + index, + }); + + const { settings } = await this.getIndexConfig(index); + + return settings; + } catch (error) { + throw new HttpException( + `updateIndexSettings failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async getIndexConfig(index = this.defaultIndex) { + try { + const [settings, mappings] = await Promise.all([ + this.osClient.indices.getSettings({ index }), + this.osClient.indices.getMapping({ index }), + ]); + + return { + settings: settings.body[index].settings, + mappings: mappings.body[index].mappings, + }; + } catch (error) { + throw new HttpException( + `getIndexConfig failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async deleteIndex(index = this.defaultIndex) { + try { + await this.osClient.indices.delete({ index }); + Logger.log(`Opensearch Index Deleted-> Index: ${index} `, "Opensearch"); + return { success: true, message: `Index ${index} deleted` }; + } catch (error) { + throw new HttpException( + `deleteIndex failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async search( + filter: ISearchFilter, + index = this.defaultIndex, + limit = 1000, + skip = 0, + ): Promise<{ totalCount: number; data: (string | undefined)[] }> { + try { + const searchQuery = this.searchService.buildSearchQuery(filter); + const searchOptions = { + track_scores: true, + sort: [{ _score: { order: "desc" } }] as unknown as Record< + string, + unknown + >[], + query: searchQuery.query, + from: skip, + size: limit, + min_score: 0.1, + track_total_hits: true, + _source: [""], + }; + + const { body } = await this.osClient.search({ + index, + body: searchOptions, + }); + + const totalCount = body.hits.hits.length || 0; + + const data = body.hits.hits.map((item) => item._id || ""); + + return { + totalCount, + data, + }; + } catch (error) { + throw new HttpException( + `SearchService || search query issue || -> search ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async updateInsertDocument(data: Partial) { + try { + await this.osClient.index({ + index: this.defaultIndex, + id: data.pid, + body: data, + refresh: this.refresh, + }); + + Logger.log( + `Document Update/inserted-> Document_id: ${data.pid} update/inserted on index: ${this.defaultIndex}`, + "Opensearch", + ); + } catch (error) { + throw new HttpException( + `updateDocument failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async deleteDocument(id: string, index = this.defaultIndex) { + try { + await this.osClient.delete({ + index, + id, + refresh: this.refresh, + }); + Logger.log( + `Document Deleted-> Document_id: ${id} deleted on index: ${index}`, + "Opensearch", + ); + } catch (error) { + throw new HttpException( + `deleteDocument failed-> OpensearchService ${error}`, + HttpStatus.BAD_REQUEST, + ); + } + } + + async checkIndexExists(index: string) { + const { body: indexExists } = await this.osClient.indices.exists({ index }); + + if (!indexExists) { + throw new Error(`Index ${index} not found`); + } + } + + // *** NOTE: below are helper methods *** + + async performBulkOperation( + collection: T[], + index: string, + ) { + const result = await this.osClient.helpers.bulk({ + retries: 5, + wait: 10000, + datasource: collection, + onDocument(doc: T) { + const { _id: mongoId, ...body } = doc; + return [ + { + index: { + _index: index, + _id: mongoId, + }, + }, + body, + ]; + }, + onDrop(doc) { + console.debug(`${doc.document._id}`, doc.error?.reason); + }, + }); + return result; + } +} diff --git a/src/opensearch/opensearch.subject.ts b/src/opensearch/opensearch.subject.ts new file mode 100644 index 000000000..f55619a9f --- /dev/null +++ b/src/opensearch/opensearch.subject.ts @@ -0,0 +1 @@ +export class Opensearch {} diff --git a/src/opensearch/providers/fields.enum.ts b/src/opensearch/providers/fields.enum.ts new file mode 100644 index 000000000..027a3d454 --- /dev/null +++ b/src/opensearch/providers/fields.enum.ts @@ -0,0 +1,4 @@ +export enum MustFields { + DatasetName = "datasetName", + Description = "description", +} diff --git a/src/elastic-search/providers/query-builder.service.spec.ts b/src/opensearch/providers/query-builder.service.spec.ts similarity index 91% rename from src/elastic-search/providers/query-builder.service.spec.ts rename to src/opensearch/providers/query-builder.service.spec.ts index bb65f6bda..d47ade637 100644 --- a/src/elastic-search/providers/query-builder.service.spec.ts +++ b/src/opensearch/providers/query-builder.service.spec.ts @@ -7,18 +7,12 @@ describe("SearchQueryService", () => { const mockSearchQueryWithoutFilters = { text: "fake text", ownerGroup: ["fake"], - creationLocation: ["fake"], - type: ["fake"], - keywords: ["fake"], isPublished: false, }; const mockSearcQueryhWitoutText = { text: "", ownerGroup: ["fake"], - creationLocation: ["fake"], - type: ["fake"], - keywords: ["fake"], isPublished: false, }; diff --git a/src/opensearch/providers/query-builder.service.ts b/src/opensearch/providers/query-builder.service.ts new file mode 100644 index 000000000..7e5455d5a --- /dev/null +++ b/src/opensearch/providers/query-builder.service.ts @@ -0,0 +1,92 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { MustFields } from "./fields.enum"; + +import { QueryContainer } from "@opensearch-project/opensearch/api/_types/_common.query_dsl"; +import { ISearchFilter } from "../interfaces/os-common.type"; + +@Injectable() +export class SearchQueryService { + readonly mustFields = [...Object.values(MustFields)]; + readonly textQuerySplitMethod = /[ ,]+/; + + public buildSearchQuery(filter: ISearchFilter) { + try { + const accessFilter = this.buildFilterFields(filter); + const textQuery = this.buildTextQuery(filter); + + return this.constructFinalQuery(accessFilter, textQuery); + } catch (err) { + Logger.error("Open search build search query failed", err); + throw err; + } + } + private buildFilterFields(fields: ISearchFilter): QueryContainer[] { + const filter: QueryContainer[] = []; + + if (fields.userGroups && fields.userGroups.length > 0) { + filter.push({ + bool: { + should: [ + { terms: { ownerGroup: fields.userGroups } }, + { terms: { accessGroup: fields.userGroups } }, + ], + minimum_should_match: 1, + }, + }); + } + if (fields.isPublished) { + filter.push({ + term: { + isPublished: true, + }, + }); + } + + return filter; + } + + private buildTextQuery(filter: ISearchFilter): QueryContainer[] { + let wildcardQueries: QueryContainer[] = []; + + if (filter.text) { + wildcardQueries = this.buildWildcardQueries(filter.text); + } + + return wildcardQueries.length > 0 + ? [{ bool: { should: wildcardQueries, minimum_should_match: 1 } }] + : []; + } + + private splitSearchText(text: string): string[] { + return text + .toLowerCase() + .trim() + .split(this.textQuerySplitMethod) + .filter(Boolean); + } + + private buildWildcardQueries(text: string): QueryContainer[] { + const terms = this.splitSearchText(text); + return terms.flatMap((term) => + this.mustFields.map((fieldName) => ({ + wildcard: { [fieldName]: { value: `*${term}*` } }, + })), + ); + } + + private constructFinalQuery( + accessFilter: QueryContainer[], + textQuery: QueryContainer[], + ) { + const finalQuery = { + query: { + bool: { + filter: accessFilter, + must: textQuery, + }, + }, + }; + + return finalQuery; + } +} diff --git a/src/opensearch/utils/dataset-opensearch.utils.ts b/src/opensearch/utils/dataset-opensearch.utils.ts new file mode 100644 index 000000000..210cc8e99 --- /dev/null +++ b/src/opensearch/utils/dataset-opensearch.utils.ts @@ -0,0 +1,16 @@ +// It controlles which fields of the dataset document should be included +// when sending it to Opensearch. +export const DATASET_OPENSEARCH_FIELDS = [ + "pid", + "description", + "datasetName", + "isPublished", + "ownerGroup", + "accessGroups", +] as const; + +// OUTPUT EXAMPLE: +// { description: 1, datasetName: 1, isPublished: 1, ownerGroup: 1, accessGroups: 1 } +export const DATASET_OPENSEARCH_PROJECTION = Object.fromEntries( + DATASET_OPENSEARCH_FIELDS.map((key) => [key, 1]), +); diff --git a/src/origdatablocks/origdatablocks.v4.controller.ts b/src/origdatablocks/origdatablocks.v4.controller.ts index 5bde65bc7..a45577b28 100644 --- a/src/origdatablocks/origdatablocks.v4.controller.ts +++ b/src/origdatablocks/origdatablocks.v4.controller.ts @@ -501,7 +501,7 @@ export class OrigDatablocksV4Controller { description: "Database filters to apply when retrieving origdatablocks", required: false, type: String, - example: getSwaggerOrigDatablockFilterContent(), + content: getSwaggerOrigDatablockFilterContent(), }) @ApiResponse({ status: HttpStatus.OK, diff --git a/src/policies/policies.service.spec.ts b/src/policies/policies.service.spec.ts index 9ca0c1877..0fd9ca384 100644 --- a/src/policies/policies.service.spec.ts +++ b/src/policies/policies.service.spec.ts @@ -56,7 +56,7 @@ describe("PoliciesService", () => { ], }).compile(); - service = module.get(PoliciesService); + service = await module.resolve(PoliciesService); policyModel = module.get>(getModelToken("Policy")); }); diff --git a/src/proposals/proposals.controller.ts b/src/proposals/proposals.controller.ts index ae661246d..dfad2a957 100644 --- a/src/proposals/proposals.controller.ts +++ b/src/proposals/proposals.controller.ts @@ -982,10 +982,7 @@ export class ProposalsController { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); + const canViewPublic = ability.can( Action.DatasetReadManyPublic, DatasetClass, @@ -994,9 +991,6 @@ export class ProposalsController { fields.userGroups = user.currentGroups ?? []; fields.userGroups.push(...user.currentGroups); // fields.sharedWith = user.email; - } else if (canViewOwner) { - fields.ownerGroup = user.currentGroups ?? []; - fields.ownerGroup.push(...user.currentGroups); } else if (canViewPublic) { fields.isPublished = true; } diff --git a/src/proposals/proposals.module.ts b/src/proposals/proposals.module.ts index d1086eb3c..00c0cbaf5 100644 --- a/src/proposals/proposals.module.ts +++ b/src/proposals/proposals.module.ts @@ -12,11 +12,13 @@ import { GenericHistorySchema, } from "src/common/schemas/generic-history.schema"; import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; +import { MetadataKeysModule } from "src/metadata-keys/metadatakeys.module"; @Module({ imports: [ CaslModule, AttachmentsModule, + MetadataKeysModule, forwardRef(() => DatasetsModule), MongooseModule.forFeature([ { diff --git a/src/proposals/proposals.service.spec.ts b/src/proposals/proposals.service.spec.ts index 736369e04..670ba5007 100644 --- a/src/proposals/proposals.service.spec.ts +++ b/src/proposals/proposals.service.spec.ts @@ -3,6 +3,12 @@ import { Test, TestingModule } from "@nestjs/testing"; import { Model } from "mongoose"; import { ProposalsService } from "./proposals.service"; import { ProposalClass } from "./schemas/proposal.schema"; +import { MetadataKeysService } from "src/metadata-keys/metadatakeys.service"; + +class MetadataKeysServiceMock { + insertManyFromSource = jest.fn().mockResolvedValue([]); + replaceManyFromSource = jest.fn().mockResolvedValue(undefined); +} const mockProposal: ProposalClass = { proposalId: "ABCDEF", @@ -47,6 +53,7 @@ describe("ProposalsService", () => { exec: jest.fn(), }, }, + { provide: MetadataKeysService, useClass: MetadataKeysServiceMock }, ], }).compile(); diff --git a/src/proposals/proposals.service.ts b/src/proposals/proposals.service.ts index c51c4ad19..e2c2f0d8c 100644 --- a/src/proposals/proposals.service.ts +++ b/src/proposals/proposals.service.ts @@ -1,8 +1,14 @@ -import { Inject, Injectable, Scope } from "@nestjs/common"; +import { Inject, Injectable, NotFoundException, Scope } from "@nestjs/common"; import { REQUEST } from "@nestjs/core"; import { Request } from "express"; import { InjectModel } from "@nestjs/mongoose"; -import { FilterQuery, Model, PipelineStage, QueryOptions } from "mongoose"; +import { + FilterQuery, + Model, + PipelineStage, + QueryOptions, + UpdateQuery, +} from "mongoose"; import { IFacets, IFilters } from "src/common/interfaces/common.interface"; import { createFullfacetPipeline, @@ -17,15 +23,34 @@ import { IProposalFields } from "./interfaces/proposal-filters.interface"; import { ProposalClass, ProposalDocument } from "./schemas/proposal.schema"; import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; import { CreateMeasurementPeriodDto } from "./dto/create-measurement-period.dto"; +import { + MetadataKeysService, + MetadataSourceDoc, +} from "src/metadata-keys/metadatakeys.service"; @Injectable({ scope: Scope.REQUEST }) export class ProposalsService { constructor( @InjectModel(ProposalClass.name) private proposalModel: Model, + private metadataKeysService: MetadataKeysService, @Inject(REQUEST) private request: Request, ) {} + private createMetadataKeysInstance( + doc: UpdateQuery, + ): MetadataSourceDoc { + const source: MetadataSourceDoc = { + sourceType: "proposal", + sourceId: doc.proposalId, + ownerGroup: doc.ownerGroup, + accessGroups: doc.accessGroups || [], + isPublished: doc.isPublished || false, + metadata: doc.metadata ?? {}, + }; + return source; + } + async create(createProposalDto: CreateProposalDto): Promise { const username = (this.request.user as JWTUser).username; if (createProposalDto.MeasurementPeriodList) { @@ -40,7 +65,12 @@ export class ProposalsService { const createdProposal = new this.proposalModel( addCreatedByFields(createProposalDto, username), ); - return createdProposal.save(); + const savedProposal = await createdProposal.save(); + + this.metadataKeysService.insertManyFromSource( + this.createMetadataKeysInstance(savedProposal), + ); + return savedProposal; } async findAll( @@ -119,9 +149,7 @@ export class ProposalsService { ): Promise { const username = (this.request.user as JWTUser).username; - // Use findOneAndUpdate instead of manually updating the document - // This ensures the history plugin middleware is triggered - return this.proposalModel + const updatedProposal = await this.proposalModel .findOneAndUpdate( filter, { @@ -135,10 +163,37 @@ export class ProposalsService { }, ) .exec(); + + if (!updatedProposal) { + throw new NotFoundException( + `Proposal not found with filter: ${JSON.stringify(filter)}`, + ); + } + + await this.metadataKeysService.replaceManyFromSource( + this.createMetadataKeysInstance(updatedProposal), + ); + + return updatedProposal; } async remove(filter: FilterQuery): Promise { - return this.proposalModel.findOneAndDelete(filter).exec(); + const deletedProposal = await this.proposalModel + .findOneAndDelete(filter) + .exec(); + + if (!deletedProposal) { + throw new NotFoundException( + `Proposal not found with filter: ${JSON.stringify(filter)}`, + ); + } + + this.metadataKeysService.deleteMany({ + sourceType: "proposal", + sourceId: deletedProposal.proposalId, + }); + + return deletedProposal; } async incrementNumberOfDatasets(proposalIds: string[]) { diff --git a/src/published-data/dto/published-data-config.dto.ts b/src/published-data/dto/published-data-config.dto.ts new file mode 100644 index 000000000..d28aabbd5 --- /dev/null +++ b/src/published-data/dto/published-data-config.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsObject } from "class-validator"; + +export class PublishedDataConfigDto { + @IsObject() + @ApiProperty({ + description: + "[JSON schema](https://json-schema.org/docs) defining the structure for the metadata property of PublishedData objects.", + }) + metadataSchema: Record; + + @IsObject() + @ApiProperty({ + description: + "[UI schema](https://jsonforms.io/docs/uischema/) to use in the frontend for metadata edition", + }) + uiSchema: Record; +} diff --git a/src/published-data/dto/published-data.obsolete.dto.ts b/src/published-data/dto/published-data.obsolete.dto.ts index 1cbe7cb33..3b26342c4 100644 --- a/src/published-data/dto/published-data.obsolete.dto.ts +++ b/src/published-data/dto/published-data.obsolete.dto.ts @@ -11,12 +11,14 @@ import { PublishedDataStatus } from "../interfaces/published-data.interface"; import { PublishedData } from "../schemas/published-data.schema"; import { createDeepMapper } from "src/common/utils/deep-mapper.util"; -export const publishedDataV3toV4FieldMap: Record = { +export const publishedDataV3toV4FieldMap: Partial< + Record +> = { pidArray: "datasetPids", - creator: "metadata.creators.name", - authors: "metadata.contributors.name", + creator: "metadata.creators.[].name", + authors: "metadata.contributors.[].name", publisher: "metadata.publisher.name", - relatedPublications: "metadata.relatedIdentifiers.relatedIdentifier", + relatedPublications: "metadata.relatedIdentifiers.[].relatedIdentifier", affiliation: "metadata.affiliation", publicationYear: "metadata.publicationYear", url: "metadata.url", diff --git a/src/published-data/interfaces/published-data.interface.ts b/src/published-data/interfaces/published-data.interface.ts index 7eda17f50..b67ccd552 100644 --- a/src/published-data/interfaces/published-data.interface.ts +++ b/src/published-data/interfaces/published-data.interface.ts @@ -1,7 +1,7 @@ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { FilterQuery } from "mongoose"; -import { PublishedDataDocument } from "../schemas/published-data.schema"; import { ILimitsFilter } from "src/common/interfaces/common.interface"; +import { PublishedDataDocument } from "../schemas/published-data.schema"; export interface IPublishedDataFilters { where?: FilterQuery; @@ -32,6 +32,9 @@ export class FormPopulateData { @ApiPropertyOptional() thumbnail?: string; + + @ApiPropertyOptional() + metadata?: object; } export interface IRegister { diff --git a/src/published-data/pipes/filter.pipe.ts b/src/published-data/pipes/filter.pipe.ts index efa9c8940..5acbe70a8 100644 --- a/src/published-data/pipes/filter.pipe.ts +++ b/src/published-data/pipes/filter.pipe.ts @@ -5,7 +5,7 @@ import { } from "../schemas/published-data.schema"; import { publishedDataV3toV4FieldMap } from "../dto/published-data.obsolete.dto"; import { PipeTransform } from "@nestjs/common"; -import { isEmpty } from "lodash"; +import { isEmpty, mapValues } from "lodash"; import { IPublishedDataFilters } from "../interfaces/published-data.interface"; import { FilterQuery } from "mongoose"; @@ -22,8 +22,13 @@ class AppendFieldsToFilterPipe implements PipeTransform { } } +const publishedDataV3toV4FilterMap = mapValues( + publishedDataV3toV4FieldMap, + (val) => val?.replace(/\[\]\.?/g, ""), +); + export const V3_FILTER_PIPE = [ - new FilterPipe({ apiToDBMap: publishedDataV3toV4FieldMap }), + new FilterPipe({ apiToDBMap: publishedDataV3toV4FilterMap }), ]; export const V4_FILTER_PIPE = [ diff --git a/src/published-data/published-data.controller.spec.ts b/src/published-data/published-data.controller.spec.ts index b17ec39b3..accf61202 100644 --- a/src/published-data/published-data.controller.spec.ts +++ b/src/published-data/published-data.controller.spec.ts @@ -38,7 +38,9 @@ describe("PublishedDataController", () => { ], }).compile(); - controller = module.get(PublishedDataController); + controller = await module.resolve( + PublishedDataController, + ); }); it("should be defined", () => { diff --git a/src/published-data/published-data.module.ts b/src/published-data/published-data.module.ts index 3878ac7bd..657caf892 100644 --- a/src/published-data/published-data.module.ts +++ b/src/published-data/published-data.module.ts @@ -4,6 +4,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; import { MongooseModule } from "@nestjs/mongoose"; import { AttachmentsModule } from "src/attachments/attachments.module"; import { CaslModule } from "src/casl/casl.module"; +import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; import { DatasetsModule } from "src/datasets/datasets.module"; import { ProposalsModule } from "src/proposals/proposals.module"; import { @@ -12,12 +13,12 @@ import { } from "../common/schemas/generic-history.schema"; import { PublishedDataController } from "./published-data.controller"; import { PublishedDataService } from "./published-data.service"; +import { PublishedDataV4Controller } from "./published-data.v4.controller"; import { PublishedData, PublishedDataSchema, } from "./schemas/published-data.schema"; -import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; -import { PublishedDataV4Controller } from "./published-data.v4.controller"; +import { ValidatorService } from "./validator.service"; @Module({ imports: [ @@ -65,6 +66,6 @@ import { PublishedDataV4Controller } from "./published-data.v4.controller"; ProposalsModule, ], controllers: [PublishedDataController, PublishedDataV4Controller], - providers: [PublishedDataService], + providers: [PublishedDataService, ValidatorService], }) export class PublishedDataModule {} diff --git a/src/published-data/published-data.service.ts b/src/published-data/published-data.service.ts index d3d929fbf..22fc4f3a8 100644 --- a/src/published-data/published-data.service.ts +++ b/src/published-data/published-data.service.ts @@ -67,13 +67,6 @@ export class PublishedDataService { ), ); - if ( - createdPublished.metadata && - !createdPublished.metadata.publicationYear - ) { - createdPublished.metadata.publicationYear = new Date().getFullYear(); - } - return createdPublished.save(); } diff --git a/src/published-data/published-data.v4.controller.spec.ts b/src/published-data/published-data.v4.controller.spec.ts index eb125bd38..44cc1fa1e 100644 --- a/src/published-data/published-data.v4.controller.spec.ts +++ b/src/published-data/published-data.v4.controller.spec.ts @@ -9,6 +9,7 @@ import { ProposalsService } from "src/proposals/proposals.service"; import { PublishedDataService } from "./published-data.service"; import { PublishedDataV4Controller } from "./published-data.v4.controller"; import { PublishedData } from "./schemas/published-data.schema"; +import { ValidatorService } from "./validator.service"; class AttachmentsServiceMock {} @@ -23,6 +24,8 @@ class PublishedDataServiceMock {} class CaslAbilityFactoryMock {} +class ValidatorServiceMock {} + class ConfigServiceMock { get(key: string) { const config = { @@ -51,6 +54,10 @@ describe("PublishedDataController", () => { ...defaultUrl, metadata: { landingPage: "custom-landingpage/" }, }; + const customLandingPageWithProtocol: PublishedData = { + ...defaultUrl, + metadata: { landingPage: "https://custom-landingpage/" }, + }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -65,6 +72,7 @@ describe("PublishedDataController", () => { { provide: PublishedDataService, useClass: PublishedDataServiceMock }, { provide: CaslAbilityFactory, useClass: CaslAbilityFactoryMock }, { provide: ConfigService, useClass: ConfigServiceMock }, + { provide: ValidatorService, useClass: ValidatorServiceMock }, ], }).compile(); @@ -90,4 +98,13 @@ describe("PublishedDataController", () => { `https://${customLandingPage.metadata!.landingPage}${encodeURIComponent(customLandingPage.doi)}`, ); }); + + it("should not double-prefix https:// when 'landingPage' already includes a protocol", () => { + expect( + controller.doiRegistrationJSON(customLandingPageWithProtocol), + ).toHaveProperty( + "data.attributes.url", + `${customLandingPageWithProtocol.metadata!.landingPage}${encodeURIComponent(customLandingPageWithProtocol.doi)}`, + ); + }); }); diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 824a7829a..3101aa75f 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -25,7 +25,7 @@ import { ApiTags, } from "@nestjs/swagger"; import { Request } from "express"; -import { Validator } from "jsonschema"; +import { cloneDeep } from "lodash"; import { FilterQuery, QueryOptions } from "mongoose"; import { firstValueFrom } from "rxjs"; import { AttachmentsService } from "src/attachments/attachments.service"; @@ -36,6 +36,7 @@ import { AppAbility, CaslAbilityFactory } from "src/casl/casl-ability.factory"; import { CheckPolicies } from "src/casl/decorators/check-policies.decorator"; import { AuthenticatedPoliciesGuard } from "src/casl/guards/auth-check.guard"; import { PoliciesGuard } from "src/casl/guards/policies.guard"; +import { ILimitsFilter } from "src/common/interfaces/common.interface"; import { handleAxiosRequestError } from "src/common/utils"; import { DatasetsService } from "src/datasets/datasets.service"; import { DatasetsV4Controller } from "src/datasets/datasets.v4.controller"; @@ -50,14 +51,15 @@ import { IRegister, PublishedDataStatus, } from "./interfaces/published-data.interface"; +import { V4_FILTER_PIPE } from "./pipes/filter.pipe"; import { RegisteredFilterPipe } from "./pipes/registered.pipe"; import { PublishedDataService } from "./published-data.service"; import { PublishedData, PublishedDataDocument, } from "./schemas/published-data.schema"; -import { V4_FILTER_PIPE } from "./pipes/filter.pipe"; -import { ILimitsFilter } from "src/common/interfaces/common.interface"; +import { ValidatorService } from "./validator.service"; +import { PublishedDataConfigDto } from "./dto/published-data-config.dto"; @ApiBearerAuth() @ApiTags("published data v4") @@ -77,10 +79,15 @@ export class PublishedDataV4Controller { private readonly proposalsService: ProposalsService, private readonly publishedDataService: PublishedDataService, private caslAbilityFactory: CaslAbilityFactory, + private validatorService: ValidatorService, ) {} @AllowAny() @Get("config") + @ApiResponse({ + status: HttpStatus.OK, + type: PublishedDataConfigDto, + }) async getConfig(): Promise | null> { return this.publishedDataService.getConfig(); } @@ -222,6 +229,9 @@ export class PublishedDataV4Controller { name: "pid", description: "Dataset pid used to fetch form data.", required: true, + type: String, + isArray: true, + explode: true, }) @ApiResponse({ status: HttpStatus.OK, @@ -229,10 +239,11 @@ export class PublishedDataV4Controller { isArray: false, description: "Return form populate data", }) - async formPopulate(@Query("pid") pid: string) { + async formPopulate(@Query("pid") pid: string[] | string) { + pid = Array.isArray(pid) ? pid : [pid]; const formData: FormPopulateData = {}; const dataset = (await this.datasetsService.findOne({ - where: { pid }, + where: { pid: pid[0] }, })) as unknown as DatasetClass; let proposalId; @@ -262,6 +273,13 @@ export class PublishedDataV4Controller { formData.thumbnail = attachment.thumbnail; } + const dto: PartialUpdatePublishedDataV4Dto = { + datasetPids: pid, + metadata: {}, + }; + await this.validatorService.validate(dto); + formData.metadata = dto.metadata; + return formData; } @@ -408,7 +426,11 @@ export class PublishedDataV4Controller { ); } - await this.validateMetadata(publishedData.metadata); + const validationErrors = + await this.validatorService.validate(publishedData); + if (validationErrors) { + throw new HttpException(validationErrors, HttpStatus.BAD_REQUEST); + } // Make datasets in publishedData datasetPids array public const datasetPids = publishedData.datasetPids; @@ -476,29 +498,6 @@ export class PublishedDataV4Controller { ); } - async validateMetadata(metadata?: object) { - const validator = new Validator(); - const metadataConfig = await this.getConfig(); - if (!metadataConfig?.metadataSchema) { - throw new HttpException( - "Published data schema is not defined in the configuration.", - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - - const validationResult = validator.validate( - metadata, - metadataConfig.metadataSchema, - ); - - if (!validationResult.valid) { - throw new HttpException( - validationResult.errors.map((error) => error.stack), - HttpStatus.BAD_REQUEST, - ); - } - } - // DELETE /publisheddata/:id @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies("publisheddata", (ability: AppAbility) => @@ -567,14 +566,24 @@ export class PublishedDataV4Controller { publishedData.registeredTime = data.registeredTime; publishedData.status = data.status; - await this.validateMetadata(publishedData.metadata); + const validationErrors = + await this.validatorService.validate(publishedData); + if (validationErrors) { + throw new HttpException(validationErrors, HttpStatus.BAD_REQUEST); + } + const mergePatchRequest = cloneDeep(request); + mergePatchRequest.headers["content-type"] = "application/merge-patch+json"; await Promise.all( publishedData.datasetPids.map(async (pid) => { - await this.datasetsController.findByIdAndUpdate(request, pid, { - isPublished: true, - datasetlifecycle: { publishedOn: data.registeredTime }, - }); + await this.datasetsController.findByIdAndUpdate( + mergePatchRequest, + pid, + { + isPublished: true, + datasetlifecycle: { publishedOn: data.registeredTime }, + }, + ); }), ); @@ -733,8 +742,13 @@ export class PublishedDataV4Controller { landingPage, } = metadata ?? {}; + const landingPageBase = + typeof landingPage === "string" && + (landingPage.startsWith("https://") || landingPage.startsWith("http://")) + ? landingPage + : `https://${landingPage}`; const url = landingPage - ? `https://${landingPage}${encodeURIComponent(doi)}` + ? `${landingPageBase}${encodeURIComponent(doi)}` : `${this.configService.get("publicURLprefix")}${encodeURIComponent(doi)}`; const descriptionsArray = [ diff --git a/src/published-data/validator.service.spec.ts b/src/published-data/validator.service.spec.ts new file mode 100644 index 000000000..7da657dbe --- /dev/null +++ b/src/published-data/validator.service.spec.ts @@ -0,0 +1,190 @@ +import { ConfigService } from "@nestjs/config"; +import { Test, TestingModule } from "@nestjs/testing"; +import { AttachmentsService } from "src/attachments/attachments.service"; +import { DatasetsService } from "src/datasets/datasets.service"; +import { ProposalsService } from "src/proposals/proposals.service"; +import { ReadOnlyDatasetsService, ValidatorService } from "./validator.service"; +import { ErrorObject } from "ajv"; + +describe("ValidatorService", () => { + let service: ValidatorService; + + const mockConfigService = { + get: jest.fn(), + }; + + const mockDataService = { + findOne: jest.fn(), + findAll: jest.fn(), + count: jest.fn(), + }; + + const createService = async (publishedDataConfig: unknown) => { + mockConfigService.get.mockImplementation((key: string) => { + if (key === "publishedDataConfig") return publishedDataConfig; + return null; + }); + + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ValidatorService, + { provide: ConfigService, useValue: mockConfigService }, + { provide: ProposalsService, useValue: mockDataService }, + { provide: DatasetsService, useValue: mockDataService }, + { provide: AttachmentsService, useValue: mockDataService }, + ], + }).compile(); + + return module.get(ValidatorService); + }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it("should be defined", async () => { + service = await createService({ metadataSchema: {} }); + expect(service).toBeDefined(); + }); + + describe("validate", () => { + it("should be a no-op if metadataSchema is missing", async () => { + service = await createService({}); + const errors = await service.validate({}); + expect(errors).toBeNull(); + }); + + it("should return null when metadata is valid", async () => { + const schema = { + type: "object", + properties: { name: { type: "string" } }, + required: ["name"], + }; + + service = await createService({ metadataSchema: schema }); + + const mockData = { metadata: { name: "abc" } }; + const errors = await service.validate(mockData); + expect(errors).toBeNull(); + }); + + it("should return errors when metadata is invalid", async () => { + const schema = { + type: "object", + properties: { name: { type: "string" } }, + required: ["name"], + }; + + service = await createService({ metadataSchema: schema }); + + const mockData = { metadata: { invalidKey: 5 } }; + const errors = await service.validate(mockData); + + expect(errors).toBeDefined(); + expect(Array.isArray(errors)).toBe(true); + const errorList = errors! as ErrorObject< + string, + Record, + unknown + >[]; + expect(errorList.length).toBe(1); + expect(errorList[0].message).toBe("must have required property 'name'"); + }); + }); + + describe("Dynamic Defaults", () => { + it("should handle pre-defined dynamic default (currentYear)", async () => { + const schema = { + type: "object", + required: ["publicationYear"], + allOf: [ + { dynamicDefaults: { publicationYear: "currentYear" } }, + { properties: { publicationYear: { type: "number" } } }, + ], + }; + + service = await createService({ metadataSchema: schema }); + + const mockData = { metadata: {} }; + const errors = await service.validate(mockData); + expect(errors).toBeNull(); + + const metadata = mockData.metadata as Record; + expect(metadata.publicationYear).toBe(new Date().getFullYear()); + }); + + it("should handle user-defined dynamic default (sync)", async () => { + const schema = { + type: "object", + required: ["publicationYear"], + allOf: [ + { dynamicDefaults: { publicationYear: "userDefinedFunction" } }, + { properties: { publicationYear: { type: "number" } } }, + ], + }; + + service = await createService({ metadataSchema: schema }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (service as any).dynamicDefaults.set( + "userDefinedFunction", + () => () => 5, + ); + + const mockData = { metadata: {} }; + const errors = await service.validate(mockData); + expect(errors).toBeNull(); + + const metadata = mockData.metadata as Record; + expect(metadata.publicationYear).toBe(5); + }); + + it("should handle user-defined dynamic default (async)", async () => { + const schema = { + type: "object", + required: ["publicationYear"], + allOf: [ + { dynamicDefaults: { publicationYear: "userDefinedAsyncFunction" } }, + { properties: { publicationYear: { type: "number" } } }, + ], + }; + + service = await createService({ metadataSchema: schema }); + + mockDataService.count.mockImplementation(() => 6); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (service as any).dynamicDefaults.set( + "userDefinedAsyncFunction", + async function (ctx: { datasetsService: ReadOnlyDatasetsService }) { + const datasetsCount = await ctx.datasetsService.count({}); + return () => datasetsCount; + }, + ); + + const mockData = { metadata: {} }; + const errors = await service.validate(mockData); + expect(errors).toBeNull(); + + const metadata = mockData.metadata as Record; + expect(metadata.publicationYear).toBe(6); + }); + + it("should error on unknown dynamicDefaults functions", async () => { + const schema = { + type: "object", + required: ["publicationYear"], + allOf: [ + { dynamicDefaults: { publicationYear: "notImplemented" } }, + { properties: { publicationYear: { type: "number" } } }, + ], + }; + + service = await createService({ metadataSchema: schema }); + + const mockData = { metadata: {} }; + await expect(service.validate(mockData)).rejects.toThrow( + 'invalid "dynamicDefaults" keyword property value: notImplemented', + ); + }); + }); +}); diff --git a/src/published-data/validator.service.ts b/src/published-data/validator.service.ts new file mode 100644 index 000000000..80550fc93 --- /dev/null +++ b/src/published-data/validator.service.ts @@ -0,0 +1,158 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import addFormats from "ajv-formats"; +import addKeywords from "ajv-keywords"; +import def, { + DynamicDefaultFunc, +} from "ajv-keywords/dist/definitions/dynamicDefaults"; +import Ajv2019, { Schema } from "ajv/dist/2019"; +import { isArray, isEmpty, isMap, isNil } from "lodash"; +import { AttachmentsService } from "src/attachments/attachments.service"; +import { DatasetsService } from "src/datasets/datasets.service"; +import { ProposalsService } from "src/proposals/proposals.service"; +import { CreatePublishedDataV4Dto } from "./dto/create-published-data.v4.dto"; +import { + PartialUpdatePublishedDataV4Dto, + UpdatePublishedDataV4Dto, +} from "./dto/update-published-data.v4.dto"; +import { PublishedDataConfigDto } from "./dto/published-data-config.dto"; + +export type ReadOnlyProposalsService = Pick< + ProposalsService, + "findOne" | "findAll" | "count" +>; +export type ReadOnlyDatasetsService = Pick< + DatasetsService, + "findOne" | "findAll" | "count" +>; +export type ReadOnlyAttachmentsService = Pick< + AttachmentsService, + "findOne" | "findAll" | "count" +>; + +@Injectable() +export class ValidatorService { + private ajv: Ajv2019; + private config: PublishedDataConfigDto; + private dynamicDefaults: Map = new Map([ + ["currentYear", () => () => new Date().getFullYear()], + ]); + + constructor( + private readonly configService: ConfigService, + private readonly proposalsService: ProposalsService, + private readonly datasetsService: DatasetsService, + private readonly attachmentsService: AttachmentsService, + ) { + this.ajv = new Ajv2019({ + useDefaults: "empty", + allErrors: true, + strict: false, + }); + addFormats(this.ajv); + addKeywords(this.ajv); + + this.config = this.configService.get( + "publishedDataConfig", + { metadataSchema: {}, uiSchema: {} }, + ); + + if (isNil(this.config.metadataSchema)) { + return; + } + + const modulePath = this.configService.get("ajvCustomDefinitions"); + if (isEmpty(modulePath)) { + return; + } + + try { + const externalModule = this.loadExternalModule(modulePath!); + + if (isArray(externalModule.keywords)) { + for (const definition of externalModule.keywords) { + Logger.log(`Adding ajv keyword: '${definition.keyword}'`); + this.ajv.addKeyword(definition); + } + } + + if (isMap(externalModule.dynamicDefaults)) { + this.dynamicDefaults = new Map([ + ...this.dynamicDefaults, + ...externalModule.dynamicDefaults, + ]); + } + } catch (error) { + Logger.error(`Failed to load module at '${modulePath}'`, error); + throw error; + } + } + + async validate( + publishedData: + | CreatePublishedDataV4Dto + | UpdatePublishedDataV4Dto + | PartialUpdatePublishedDataV4Dto, + ) { + if (isNil(this.config.metadataSchema)) { + return null; + } + + await this.loadDynamicDefaultFunctions(publishedData); + + const validateFn = this.ajv.compile(this.config.metadataSchema as Schema); + validateFn(publishedData.metadata); + return validateFn.errors; + } + + private loadExternalModule(path: string) { + Logger.debug(`Loading custom ajv code at ${path}`); + // eslint-disable-next-line @typescript-eslint/no-require-imports + const externalModule = require(path); + + return externalModule; + } + + private async loadDynamicDefaultFunctions( + publishedData: + | CreatePublishedDataV4Dto + | UpdatePublishedDataV4Dto + | PartialUpdatePublishedDataV4Dto, + ) { + for (const [name, implementation] of this.dynamicDefaults.entries()) { + if (typeof implementation !== "function") { + Logger.error( + `Ignoring dynamic defaults function ${name} should be of type 'function' not '${typeof implementation}'.`, + ); + continue; + } + switch (implementation.constructor.name) { + case "Function": + def.DEFAULTS[name] = implementation; + break; + case "AsyncFunction": + /** + * Ajv cannot 'await' during validation. To get around this, we run the + * AsyncFunction now to perform any setup (like DB queries). + */ + try { + const syncFunc = await implementation({ + publishedData: publishedData, + proposalService: this + .proposalsService as ReadOnlyProposalsService, + datasetsService: this.datasetsService as ReadOnlyDatasetsService, + attachmentsService: this + .attachmentsService as ReadOnlyAttachmentsService, + }); + def.DEFAULTS[name] = () => syncFunc; + } catch (err) { + throw new Error( + `Executing dynamicDefaults function '${name}' failed with the following error:`, + { cause: err }, + ); + } + break; + } + } + } +} diff --git a/src/samples/dto/output-sample.dto.ts b/src/samples/dto/output-sample.dto.ts index b871939ef..e92f9deb1 100644 --- a/src/samples/dto/output-sample.dto.ts +++ b/src/samples/dto/output-sample.dto.ts @@ -1,6 +1,8 @@ import { ApiProperty } from "@nestjs/swagger"; import { IsDateString, IsString } from "class-validator"; import { CreateSampleDto } from "./create-sample.dto"; +import { Transform } from "class-transformer"; +import { decodeScientificMetadataKeys } from "src/common/utils"; export class OutputSampleDto extends CreateSampleDto { @ApiProperty({ @@ -41,10 +43,19 @@ export class OutputSampleDto extends CreateSampleDto { @ApiProperty({ type: String, - required: true, + required: false, description: "Version of the API used when the dataset was created or last updated. API version is defined in code for each release. Managed by the system.", }) @IsString() - version: string; + version?: string; + + @ApiProperty({ + type: Object, + required: false, + default: {}, + description: "JSON object containing the sample characteristics metadata.", + }) + @Transform(({ value }) => decodeScientificMetadataKeys(value)) + declare sampleCharacteristics?: Record; } diff --git a/src/samples/dto/update-sample.dto.ts b/src/samples/dto/update-sample.dto.ts index 51d1e178e..1927055cc 100644 --- a/src/samples/dto/update-sample.dto.ts +++ b/src/samples/dto/update-sample.dto.ts @@ -1,6 +1,8 @@ import { PartialType } from "@nestjs/swagger"; import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator"; import { OwnableDto } from "../../common/dto/ownable.dto"; +import { Transform } from "class-transformer"; +import { encodeScientificMetadataKeys } from "src/common/utils"; export class UpdateSampleDto extends OwnableDto { /** @@ -43,7 +45,8 @@ export class UpdateSampleDto extends OwnableDto { */ @IsObject() @IsOptional() - readonly sampleCharacteristics?: Record = {}; + @Transform(({ value }) => encodeScientificMetadataKeys(value)) + sampleCharacteristics?: Record; /** * Flag is true when data are made publicly available. diff --git a/src/samples/samples.controller.spec.ts b/src/samples/samples.controller.spec.ts index da3057982..6cd3a9c65 100644 --- a/src/samples/samples.controller.spec.ts +++ b/src/samples/samples.controller.spec.ts @@ -45,7 +45,7 @@ describe("SamplesController", () => { describe("update", () => { const sampleId = "sample123"; - const updateDto: PartialUpdateSampleDto = { name: "Updated Sample" }; + const updateDto: PartialUpdateSampleDto = { description: "Updated Sample" }; const mockRequest = {} as Request; it("should update sample when header is missing", async () => { @@ -53,11 +53,21 @@ describe("SamplesController", () => { _id: sampleId, updatedAt: new Date("2023-01-01"), } as SampleClass; - samplesService.findOne.mockResolvedValue(sample); - samplesService.update.mockResolvedValue({ ...sample, ...updateDto }); + + const updatedSample = { + ...sample, + ...updateDto, + toObject: jest.fn().mockReturnValue({ ...sample, ...updateDto }), + }; + + samplesService.findOne = jest.fn().mockResolvedValue(sample); + samplesService.update = jest.fn().mockResolvedValue(updatedSample); jest - .spyOn(controller, "checkPermissionsForSample") + .spyOn( + controller, + "checkPermissionsForSample" as keyof SamplesController, + ) .mockResolvedValue(sample); const result = await controller.update( @@ -66,11 +76,11 @@ describe("SamplesController", () => { updateDto, {}, ); - expect(result).toEqual({ ...sample, ...updateDto }); + expect(result).toBeDefined(); }); it("should throw NotFoundException if sample not found", async () => { - samplesService.findOne.mockResolvedValue(null); + samplesService.findOne = jest.fn().mockResolvedValue(null); await expect( controller.update(mockRequest, sampleId, updateDto, {}), @@ -82,10 +92,13 @@ describe("SamplesController", () => { _id: sampleId, updatedAt: new Date("2023-01-01"), } as SampleClass; - samplesService.findOne.mockResolvedValue(sample); + samplesService.findOne = jest.fn().mockResolvedValue(sample); jest - .spyOn(controller, "checkPermissionsForSample") + .spyOn( + controller, + "checkPermissionsForSample" as keyof SamplesController, + ) .mockResolvedValue(sample); const headers = { @@ -96,13 +109,24 @@ describe("SamplesController", () => { controller.update(mockRequest, sampleId, updateDto, headers), ).rejects.toThrow(HttpException); }); + it("should update sample if header date is invalid", async () => { const sample = { _id: sampleId, updatedAt: new Date() } as SampleClass; - samplesService.findOne.mockResolvedValue(sample); - samplesService.update.mockResolvedValue({ ...sample, ...updateDto }); + + const updatedSample = { + ...sample, + ...updateDto, + toObject: jest.fn().mockReturnValue({ ...sample, ...updateDto }), + }; + + samplesService.findOne = jest.fn().mockResolvedValue(sample); + samplesService.update = jest.fn().mockResolvedValue(updatedSample); jest - .spyOn(controller, "checkPermissionsForSample") + .spyOn( + controller, + "checkPermissionsForSample" as keyof SamplesController, + ) .mockResolvedValue(sample); const headers = { @@ -115,16 +139,26 @@ describe("SamplesController", () => { updateDto, headers, ); - expect(result).toEqual({ ...sample, ...updateDto }); + expect(result).toBeDefined(); }); it("should update sample if header date is not present", async () => { const sample = { _id: sampleId, updatedAt: new Date() } as SampleClass; - samplesService.findOne.mockResolvedValue(sample); - samplesService.update.mockResolvedValue({ ...sample, ...updateDto }); + + const updatedSample = { + ...sample, + ...updateDto, + toObject: jest.fn().mockReturnValue({ ...sample, ...updateDto }), + }; + + samplesService.findOne = jest.fn().mockResolvedValue(sample); + samplesService.update = jest.fn().mockResolvedValue(updatedSample); jest - .spyOn(controller, "checkPermissionsForSample") + .spyOn( + controller, + "checkPermissionsForSample" as keyof SamplesController, + ) .mockResolvedValue(sample); const result = await controller.update( @@ -133,7 +167,7 @@ describe("SamplesController", () => { updateDto, {}, ); - expect(result).toEqual({ ...sample, ...updateDto }); + expect(result).toBeDefined(); }); }); }); diff --git a/src/samples/samples.controller.ts b/src/samples/samples.controller.ts index f05cd5227..d857db811 100644 --- a/src/samples/samples.controller.ts +++ b/src/samples/samples.controller.ts @@ -19,6 +19,8 @@ import { Header, NotFoundException, Headers, + ClassSerializerInterceptor, + SerializeOptions, } from "@nestjs/common"; import { SamplesService } from "./samples.service"; import { CreateSampleDto } from "./dto/create-sample.dto"; @@ -70,6 +72,8 @@ import { AuthenticatedPoliciesGuard } from "src/casl/guards/auth-check.guard"; import { CountApiResponse } from "src/common/types"; import { OutputAttachmentV3Dto } from "src/attachments/dto-obsolete/output-attachment.v3.dto"; import { checkUnmodifiedSince } from "src/common/utils/check-unmodified-since"; +import { OutputSampleDto } from "./dto/output-sample.dto"; +import { DatasetDocument } from "src/datasets/schemas/dataset.schema"; export class FindByIdAccessResponse { @ApiProperty({ type: Boolean }) @@ -79,6 +83,7 @@ export class FindByIdAccessResponse { @ApiBearerAuth() @ApiTags("samples") @Controller("samples") +@UseInterceptors(ClassSerializerInterceptor) export class SamplesController { constructor( private readonly attachmentsService: AttachmentsService, @@ -174,21 +179,23 @@ export class SamplesController { id: string, group: Action, ) { - const sample = await this.samplesService.findOne({ + const sampleDoc = await this.samplesService.findOne({ sampleId: id, }); - if (!sample) { + if (!sampleDoc) { throw new NotFoundException(`Sample: ${id} not found`); } - const canDoAction = this.permissionChecker(group, sample, request); + const sampleObj = sampleDoc.toObject(); + + const canDoAction = this.permissionChecker(group, sampleObj, request); if (!canDoAction) { throw new ForbiddenException("Unauthorized to this sample"); } - return sample; + return sampleObj; } private checkPermissionsForSampleCreate( @@ -269,6 +276,10 @@ export class SamplesController { ) @HttpCode(HttpStatus.CREATED) @Post() + @SerializeOptions({ + type: OutputSampleDto, + excludeExtraneousValues: false, + }) @ApiOperation({ summary: "It creates a new sample.", description: @@ -280,20 +291,23 @@ export class SamplesController { }) @ApiResponse({ status: HttpStatus.CREATED, - type: SampleClass, + type: OutputSampleDto, description: "Create a new sample and return its representation in SciCat", }) async create( @Req() request: Request, @Body() createSampleDto: CreateSampleDto, - ): Promise { + ): Promise { const sampleDTO = this.checkPermissionsForSampleCreate( request, createSampleDto, Action.SampleCreate, ); - return this.samplesService.create(sampleDTO); + const createdSample = await this.samplesService.create(sampleDTO); + const sampleObj = (createdSample as SampleDocument).toObject(); + + return sampleObj as OutputSampleDto; } // GET /samples @@ -302,6 +316,10 @@ export class SamplesController { ability.can(Action.SampleRead, SampleClass), ) @Get() + @SerializeOptions({ + type: OutputSampleDto, + excludeExtraneousValues: false, + }) @ApiOperation({ summary: "It returns a list of samples", description: @@ -317,17 +335,22 @@ export class SamplesController { }) @ApiResponse({ status: HttpStatus.OK, - type: SampleClass, + type: OutputSampleDto, isArray: true, description: "Return the samples requested", }) async findAll( @Req() request: Request, @Query("filter") filters?: string, - ): Promise { + ): Promise { const sampleFilters: IFilters = this.updateFiltersForList(request, JSON.parse(filters ?? "{}")); - return this.samplesService.findAll(sampleFilters); + const samples = await this.samplesService.findAll(sampleFilters); + + const samplesObj = (samples as SampleDocument[]).map((sample) => + sample.toObject(), + ); + return samplesObj as OutputSampleDto[]; } // GET /samples/count @@ -393,6 +416,10 @@ export class SamplesController { ability.can(Action.SampleRead, SampleClass), ) @Get("/fullquery") + @SerializeOptions({ + type: OutputSampleDto, + excludeExtraneousValues: false, + }) @ApiOperation({ summary: "It returns a list of samples matching the query provided.", description: @@ -418,14 +445,14 @@ export class SamplesController { }) @ApiResponse({ status: HttpStatus.OK, - type: SampleClass, + type: OutputSampleDto, isArray: true, description: "Return samples requested", }) async fullquery( @Req() request: Request, @Query() filters: { fields?: string; limits?: string }, - ): Promise { + ): Promise { const user: JWTUser = request.user as JWTUser; const fields: ISampleFields = JSON.parse(filters.fields ?? "{}"); const limits: ILimitsFilter = JSON.parse(filters.limits ?? "{}"); @@ -461,7 +488,14 @@ export class SamplesController { fields, limits, }; - return this.samplesService.fullquery(parsedFilters); + + const samples = await this.samplesService.fullquery(parsedFilters); + + const samplesObj = (samples as SampleDocument[]).map((sample) => + sample.toObject(), + ); + + return samplesObj as OutputSampleDto[]; } // GET /samples/metadataKeys @@ -607,6 +641,10 @@ export class SamplesController { ) @Get("/:id") @Header("content-type", "application/json") + @SerializeOptions({ + type: OutputSampleDto, + excludeExtraneousValues: false, + }) @ApiOperation({ summary: "It returns the sample requested.", description: "It returns the sample requested through the id specified.", @@ -618,13 +656,13 @@ export class SamplesController { }) @ApiResponse({ status: HttpStatus.OK, - type: SampleClass, + type: OutputSampleDto, description: "Return sample with id specified", }) async findById( @Req() request: Request, @Param("id") id: string, - ): Promise { + ): Promise { const sample = await this.checkPermissionsForSample( request, id, @@ -675,6 +713,10 @@ export class SamplesController { ), ) @Patch("/:id") + @SerializeOptions({ + type: OutputSampleDto, + excludeExtraneousValues: false, + }) @ApiOperation({ summary: "It updates the sample.", description: @@ -691,7 +733,7 @@ export class SamplesController { }) @ApiResponse({ status: HttpStatus.OK, - type: SampleClass, + type: OutputSampleDto, description: "Update an existing sample and return its representation in SciCat", }) @@ -700,7 +742,7 @@ export class SamplesController { @Param("id") id: string, @Body() updateSampleDto: PartialUpdateSampleDto, @Headers() headers: Record, - ): Promise { + ): Promise { const sample = await this.checkPermissionsForSample( request, id, @@ -710,7 +752,14 @@ export class SamplesController { //checks if the resource is unmodified since clients timestamp checkUnmodifiedSince(sample.updatedAt, headers["if-unmodified-since"]); - return this.samplesService.update({ sampleId: id }, updateSampleDto); + const updatedSample = await this.samplesService.update( + { sampleId: id }, + updateSampleDto, + ); + + const sampleObj = (updatedSample as SampleDocument).toObject(); + + return sampleObj as OutputSampleDto; } // DELETE /samples/:id @@ -960,10 +1009,6 @@ export class SamplesController { Action.DatasetReadManyAccess, DatasetClass, ); - const canViewOwner = ability.can( - Action.DatasetReadManyOwner, - DatasetClass, - ); const canViewPublic = ability.can( Action.DatasetReadManyPublic, DatasetClass, @@ -972,19 +1017,21 @@ export class SamplesController { fields.userGroups = user.currentGroups ?? []; fields.userGroups.push(...user.currentGroups); // fields.sharedWith = user.email; - } else if (canViewOwner) { - fields.ownerGroup = user.currentGroups ?? []; - fields.ownerGroup.push(...user.currentGroups); } else if (canViewPublic) { fields.isPublished = true; } } - const dataset = await this.datasetsService.fullquery({ + const datasets = await this.datasetsService.fullquery({ where: { sampleId: id }, fields: fields, }); - return dataset; + + const datasetsObj = (datasets as DatasetDocument[]).map((dataset) => + dataset.toObject(), + ); + + return datasetsObj; } // PATCH /samples/:id/datasets/:fk diff --git a/src/samples/samples.module.ts b/src/samples/samples.module.ts index 1157b1236..100deb8f6 100644 --- a/src/samples/samples.module.ts +++ b/src/samples/samples.module.ts @@ -12,6 +12,7 @@ import { SamplesController } from "./samples.controller"; import { SamplesService } from "./samples.service"; import { SampleClass, SampleSchema } from "./schemas/sample.schema"; import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plugin.util"; +import { MetadataKeysModule } from "src/metadata-keys/metadatakeys.module"; @Module({ imports: [ @@ -19,6 +20,7 @@ import { applyHistoryPluginOnce } from "src/common/mongoose/plugins/history.plug AttachmentsModule, DatasetsModule, ConfigModule, + MetadataKeysModule, MongooseModule.forFeatureAsync([ { name: SampleClass.name, diff --git a/src/samples/samples.service.spec.ts b/src/samples/samples.service.spec.ts index 707da68d9..68d39220e 100644 --- a/src/samples/samples.service.spec.ts +++ b/src/samples/samples.service.spec.ts @@ -6,6 +6,7 @@ import { SamplesService } from "./samples.service"; import { SampleClass } from "./schemas/sample.schema"; import { ScientificRelation } from "src/common/scientific-relation.enum"; import * as utils from "../common/utils"; +import { MetadataKeysService } from "src/metadata-keys/metadatakeys.service"; jest.mock("../common/utils", () => { const mockUtils = jest.requireActual("../common/utils"); @@ -25,6 +26,11 @@ jest.mock("../common/utils", () => { }; }); +class MetadataKeysServiceMock { + insertManyFromSource = jest.fn().mockResolvedValue([]); + replaceManyFromSource = jest.fn().mockResolvedValue(undefined); +} + const mockSample: SampleClass = { _id: "testId", sampleId: "testId", @@ -60,6 +66,7 @@ describe("SamplesService", () => { exec: jest.fn(), }, }, + { provide: MetadataKeysService, useClass: MetadataKeysServiceMock }, ], }).compile(); diff --git a/src/samples/samples.service.ts b/src/samples/samples.service.ts index b88da181b..36cc88548 100644 --- a/src/samples/samples.service.ts +++ b/src/samples/samples.service.ts @@ -1,9 +1,9 @@ -import { Injectable, Inject, Scope } from "@nestjs/common"; +import { Injectable, Inject, Scope, NotFoundException } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { REQUEST } from "@nestjs/core"; import { Request } from "express"; import { InjectModel } from "@nestjs/mongoose"; -import { FilterQuery, Model, QueryOptions } from "mongoose"; +import { FilterQuery, Model, QueryOptions, UpdateQuery } from "mongoose"; import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; import { IFilters } from "src/common/interfaces/common.interface"; import { @@ -12,33 +12,59 @@ import { createFullqueryFilter, extractMetadataKeys, parseLimitFilters, + decodeMetadataKeyStrings, } from "src/common/utils"; import { CreateSampleDto } from "./dto/create-sample.dto"; import { PartialUpdateSampleDto } from "./dto/update-sample.dto"; import { ISampleFields } from "./interfaces/sample-filters.interface"; import { SampleClass, SampleDocument } from "./schemas/sample.schema"; import { CountApiResponse } from "src/common/types"; +import { OutputSampleDto } from "./dto/output-sample.dto"; +import { + MetadataKeysService, + MetadataSourceDoc, +} from "src/metadata-keys/metadatakeys.service"; @Injectable({ scope: Scope.REQUEST }) export class SamplesService { constructor( @InjectModel(SampleClass.name) private sampleModel: Model, private configService: ConfigService, + private metadataKeysService: MetadataKeysService, @Inject(REQUEST) private request: Request, ) {} + private createMetadataKeysInstance( + doc: UpdateQuery, + ): MetadataSourceDoc { + const source: MetadataSourceDoc = { + sourceType: "sample", + sourceId: doc.sampleId, + ownerGroup: doc.ownerGroup, + accessGroups: doc.accessGroups || [], + isPublished: doc.isPublished || false, + metadata: doc.sampleCharacteristics ?? {}, + }; + return source; + } + async create(createSampleDto: CreateSampleDto): Promise { const username = (this.request.user as JWTUser).username; const createdSample = new this.sampleModel( addCreatedByFields(createSampleDto, username), ); + const savedSample = await createdSample.save(); - return createdSample.save(); + this.metadataKeysService.insertManyFromSource( + this.createMetadataKeysInstance(savedSample), + ); + + return savedSample; } async findAll( filter: IFilters, - ): Promise { + ): Promise { const whereFilter: FilterQuery = filter.where ?? {}; const { limit, skip, sort } = parseLimitFilters(filter.limits); @@ -67,7 +93,7 @@ export class SamplesService { async fullquery( filter: IFilters, - ): Promise { + ): Promise { const filterQuery: FilterQuery = createFullqueryFilter( this.sampleModel, @@ -108,7 +134,15 @@ export class SamplesService { filters.limits = lm; } - const samples = await this.findAll(filters); + const whereFilter: FilterQuery = filters.where ?? {}; + const { limit, skip, sort } = parseLimitFilters(filters.limits); + + const samples = await this.sampleModel + .find(whereFilter) + .limit(limit) + .skip(skip) + .sort(sort) + .exec(); const metadataKeys = extractMetadataKeys( samples, @@ -122,13 +156,15 @@ export class SamplesService { "metadataKeysReturnLimit", ); + const decodedKeys = decodeMetadataKeyStrings(metadataKeys); + if (metadataKey && metadataKey.length > 0) { const filterKey = metadataKey.toLowerCase(); - return metadataKeys + return decodedKeys .filter((key) => key.toLowerCase().includes(filterKey)) .slice(0, returnLimit); } else { - return metadataKeys.slice(0, returnLimit); + return decodedKeys.slice(0, returnLimit); } } @@ -139,7 +175,7 @@ export class SamplesService { async update( filter: FilterQuery, updateSampleDto: PartialUpdateSampleDto, - ): Promise { + ): Promise { const username = (this.request.user as JWTUser).username; const updateData = addUpdatedByField(updateSampleDto, username); @@ -149,16 +185,42 @@ export class SamplesService { updatedAt: new Date(), }; - return this.sampleModel + const updatedSample = await this.sampleModel .findOneAndUpdate( filter, { $set: updateDataMongoose }, { new: true, runValidators: true }, ) .exec(); + + if (!updatedSample) { + throw new NotFoundException( + `Sample not found with filter: ${JSON.stringify(filter)}`, + ); + } + + await this.metadataKeysService.replaceManyFromSource( + this.createMetadataKeysInstance(updatedSample), + ); + + return updatedSample; } async remove(filter: FilterQuery): Promise { - return this.sampleModel.findOneAndDelete(filter).exec(); + const deletedSample = await this.sampleModel + .findOneAndDelete(filter) + .exec(); + + if (!deletedSample) { + throw new NotFoundException( + `Sample not found with filter: ${JSON.stringify(filter)}`, + ); + } + + this.metadataKeysService.deleteMany({ + sourceType: "sample", + sourceId: deletedSample.sampleId, + }); + return deletedSample; } } diff --git a/src/samples/schemas/sample.schema.ts b/src/samples/schemas/sample.schema.ts index 5dd782dea..89cb0cee5 100644 --- a/src/samples/schemas/sample.schema.ts +++ b/src/samples/schemas/sample.schema.ts @@ -61,6 +61,12 @@ export class SampleClass extends OwnableClass { */ @Prop({ type: Object, required: false, default: {} }) sampleCharacteristics?: Record = {}; + + /** + * Version of the API used when the sample was created or last updated. + */ + @Prop({ type: String, required: false }) + version?: string; } export class SampleWithAttachmentsAndDatasets extends SampleClass { diff --git a/test/Datablock.js b/test/Datablock.js index af0818b95..bc47fd19f 100644 --- a/test/Datablock.js +++ b/test/Datablock.js @@ -34,7 +34,7 @@ describe("Datablocks", () => { .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.EntryCreatedStatusCode) .expect("Content-Type", /json/) - + await request(appUrl) .post("/api/v3/Datasets") .send(TestData.RawCorrect) @@ -115,6 +115,24 @@ describe("Datablocks", () => { }); }); + ["filter", "where"].forEach((queryKey, index) => { + it(`004${(index + 1) * 3}: should count datablocks associated with dataset`, async () => { + var filter = { where: { _id: datablockId2 } }; + + return request(appUrl) + .get( + `/api/v3/datablocks/count?${queryKey}=${encodeURIComponent(JSON.stringify(filter))} `, + ) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => + res.body.should.have.property("count").and.equal(1) + ); + }); + }); + it("0050: should fetch datablocks associated with dataset", async () => { var filter = { where: { datasetId: datasetId } }; @@ -135,6 +153,22 @@ describe("Datablocks", () => { }); }); + ["datablockId", "datablockId2"].forEach((dbId, index) => { + it(`005${(index + 1) * 3}: should fetch datablock by id`, async () => { + const datablocks = { datablockId: datablockId, datablockId2: datablockId2 }; + const id = datablocks[dbId]; + return request(appUrl) + .get(`/api/v3/datablocks/${encodeURIComponent(id)}`) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => + res.body.should.have.property("id").and.equal(id) + ); + }); + }); + it("0060: The size and numFiles fields in the dataset should be correctly updated", async () => { return request(appUrl) .get("/api/v3/Datasets/" + encodeURIComponent(datasetId)) @@ -158,6 +192,23 @@ describe("Datablocks", () => { }); }); + ["datablockId", "datablockId2"].forEach((dbId, index) => { + it(`006${(index + 1) * 3}: should update datablock by id`, async () => { + const datablocks = { datablockId: datablockId, datablockId2: datablockId2 }; + const version = `new-version-${index}`; + return request(appUrl) + .patch(`/api/v3/datablocks/${encodeURIComponent(datablocks[dbId])}`) + .send({ version: version }) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => + res.body.should.have.property("version").and.equal(version) + ); + }); + }); + it("0070: should delete first datablock", async () => { return request(appUrl) .delete(`/api/v3/datablocks/${datablockId}`) diff --git a/test/DatasetCustom.js b/test/DatasetCustom.js index 31b7f8f56..43ed94e89 100644 --- a/test/DatasetCustom.js +++ b/test/DatasetCustom.js @@ -207,6 +207,7 @@ describe("2400: CustomDataset: Custom Type Datasets", () => { .expect("Content-Type", /json/) .then((res) => { res.body.should.have.property("valid").and.equal(false); + res.body.should.have.property("error").and.equal("datasetName must be a string"); }); }); diff --git a/test/DatasetV4.js b/test/DatasetV4.js index 36bb6aed0..6755a54cb 100644 --- a/test/DatasetV4.js +++ b/test/DatasetV4.js @@ -314,7 +314,7 @@ describe("2500: Datasets v4 tests", () => { it("0126: adds a new dataset with scientificMetadata", async () => { return request(appUrl) .post("/api/v4/datasets") - .send(TestData.ScientificMetadataForElasticSearchV4) + .send(TestData.DatasetWithScientificMetadataV4) .auth(accessTokenAdminIngestor, { type: "bearer" }) .expect(TestData.EntryCreatedStatusCode) .expect("Content-Type", /json/) @@ -331,7 +331,7 @@ describe("2500: Datasets v4 tests", () => { it("0127: should be able to add a new dataset with non-empty datasetLifecycle", async () => { const newDataset = { - ...TestData.ScientificMetadataForElasticSearchV4, + ...TestData.DatasetWithScientificMetadataV4, datasetlifecycle: { archivable: false, retrievable: true, @@ -423,7 +423,7 @@ describe("2500: Datasets v4 tests", () => { .send(proposalBody) .auth(accessTokenAdminIngestor, { type: "bearer" }); const proposalId = proposalRes.body.proposalId; - + const dataset = { ...TestData.DerivedCorrectMinV4, proposalIds: [proposalId], @@ -442,7 +442,7 @@ describe("2500: Datasets v4 tests", () => { .post("/api/v4/datasets") .send({ ...TestData.DerivedCorrectMinV4, proposalIds: [] }) .auth(accessTokenAdminIngestor, { type: "bearer" }); - + const res2 = await request(appUrl) .post("/api/v4/datasets") .send({ ...TestData.DerivedCorrectMinV4 }) @@ -458,9 +458,14 @@ describe("2500: Datasets v4 tests", () => { const proposalAfter = await request(appUrl) .get(`/api/v3/proposals/${encodeURIComponent(proposalId)}`) .auth(accessTokenAdminIngestor, { type: "bearer" }); - console.log("DEBUG numberOfDatasets: ", proposalAfter.body.numberOfDatasets); + console.log( + "DEBUG numberOfDatasets: ", + proposalAfter.body.numberOfDatasets, + ); console.log("DEBUG initialCount: ", initialCount); - proposalAfter.body.should.have.property("numberOfDatasets").and.equal(initialCount); + proposalAfter.body.should.have + .property("numberOfDatasets") + .and.equal(initialCount); }); }); @@ -775,13 +780,15 @@ describe("2500: Datasets v4 tests", () => { it("0211: should fetch dataset relation fields if provided in the filter as obj and add scopes", async () => { const filter = { where: { pid: derivedDatasetMinPid }, - include: [{ - relation: "instruments", - scope: { - where: - { uniqueName: TestData.InstrumentCorrect1.uniqueName }, fields: ["uniqueName"] - } - }], + include: [ + { + relation: "instruments", + scope: { + where: { uniqueName: TestData.InstrumentCorrect1.uniqueName }, + fields: ["uniqueName"], + }, + }, + ], }; const instrument1 = await request(appUrl) @@ -790,7 +797,7 @@ describe("2500: Datasets v4 tests", () => { .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.EntryCreatedStatusCode) - .expect("Content-Type", /json/) + .expect("Content-Type", /json/); const instrument2 = await request(appUrl) .post("/api/v3/Instruments") @@ -798,7 +805,7 @@ describe("2500: Datasets v4 tests", () => { .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.EntryCreatedStatusCode) - .expect("Content-Type", /json/) + .expect("Content-Type", /json/); await request(appUrl) .patch(`/api/v4/datasets/${encodeURIComponent(derivedDatasetMinPid)}`) @@ -818,18 +825,19 @@ describe("2500: Datasets v4 tests", () => { const [firstDataset] = res.body; firstDataset.should.have.property("pid"); - firstDataset.should.have.property("instruments").eql([{ - _id: instrument1.body.id, - uniqueName: TestData.InstrumentCorrect1.uniqueName - }] - ); + firstDataset.should.have.property("instruments").eql([ + { + _id: instrument1.body.id, + uniqueName: TestData.InstrumentCorrect1.uniqueName, + }, + ]); firstDataset.should.not.have.property("datablocks"); }); }); it("0212: should fetch specific dataset fields excluding fields provided in field", async () => { const filter = { - fields: {datasetName: 0, contactEmail: 1}, + fields: { datasetName: 0, contactEmail: 1 }, }; return request(appUrl) @@ -1096,7 +1104,9 @@ describe("2500: Datasets v4 tests", () => { .then((res) => { res.body.should.be.a("object"); res.body.should.have.property("message"); - res.body.message.should.match(/Invalid \$project :: caused by :: Path collision at origdatablocks/); + res.body.message.should.match( + /Invalid \$project :: caused by :: Path collision at origdatablocks/, + ); }); }); }); diff --git a/test/DerivedDataset.js b/test/DerivedDataset.js index deb16158d..0de7d93ea 100644 --- a/test/DerivedDataset.js +++ b/test/DerivedDataset.js @@ -83,7 +83,7 @@ describe("0700: DerivedDataset: Derived Datasets", () => { it("0110: adds a new minimal derived dataset", async () => { return request(appUrl) .post("/api/v3/Datasets") - .send({...TestData.DerivedCorrectMin, sourceFolder: "/data/derived/"}) + .send({ ...TestData.DerivedCorrectMin, sourceFolder: "/data/derived/" }) .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.EntryCreatedStatusCode) @@ -221,6 +221,7 @@ describe("0700: DerivedDataset: Derived Datasets", () => { .expect("Content-Type", /json/) .then((res) => { res.body.should.have.property("valid").and.equal(false); + res.body.should.have.property("error").and.equal("each value in inputDatasets must be a string; each value in usedSoftware must be a string"); }); }); diff --git a/test/DerivedDatasetDatablock.js b/test/DerivedDatasetDatablock.js index 4882820d7..056640c2a 100644 --- a/test/DerivedDatasetDatablock.js +++ b/test/DerivedDatasetDatablock.js @@ -385,6 +385,20 @@ describe("0750: DerivedDatasetDatablock: Test Datablocks and their relation to d }); }); + it("193: should patch datablock by id", async () => { + const version = "new-version"; + return request(appUrl) + .patch(`/api/v3/Datasets/${datasetPid}/datablocks/${datablockId1}`) + .send({ version: version, dataFileList: TestData.DataBlockCorrect.dataFileList }) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => + res.body.should.have.property("version").and.equal(version) + ); + }); + it("195: Should delete second datablock", async () => { await request(appUrl) .delete(`/api/v3/Datasets/${datasetPid}/datablocks/${datablockId2}`) diff --git a/test/ElasticSearch.js b/test/ElasticSearch.js deleted file mode 100644 index 3742493d1..000000000 --- a/test/ElasticSearch.js +++ /dev/null @@ -1,254 +0,0 @@ -"use strict"; -const { faker } = require("@faker-js/faker"); -const utils = require("./LoginUtils"); -const { TestData } = require("./TestData"); -require("dotenv").config(); - -let accessTokenAdminIngestor = null, - accessTokenArchiveManager = null, - - pid = null; - -const isESenabled = process.env.ELASTICSEARCH_ENABLED == "yes"; - -const Relation = { - GREATER_THAN: "GREATER_THAN", - LESS_THAN: "LESS_THAN", - EQUAL_TO_NUMERIC: "EQUAL_TO_NUMERIC", - EQUAL_TO_STRING: "EQUAL_TO_STRING", -}; - -const scientificMetadataFieldName = { - keyValue: "with_key_value", - unitAndValue: "with_unit_and_value_si", - number: "with_number", - string: "with_string", -}; - -const scientificMetadata = (values) => { - const scientificQuery = values.map((value) => { - return { - lhs: value.lhs, - relation: value.relation, - rhs: value.rhs, - unit: value.unit, - }; - }); - - return { - scientific: scientificQuery, - }; -}; - -(isESenabled ? describe : describe.skip)( - "ElastiSearch: CRUD, filtering and search test case", - () => { - before(async () => { - db.collection("Dataset").deleteMany({}); - - accessTokenAdminIngestor = await utils.getToken(appUrl, { - username: "adminIngestor", - password: TestData.Accounts["adminIngestor"]["password"], - }); - - accessTokenArchiveManager = await utils.getToken(appUrl, { - username: "archiveManager", - password: TestData.Accounts["archiveManager"]["password"], - }); - }); - - it("0010: adds a new raw dataset with scientificMetadata", async () => { - return request(appUrl) - .post("/api/v3/Datasets") - .send(TestData.ScientificMetadataForElasticSearch) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.EntryCreatedStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.should.have - .property("scientificMetadata") - .which.is.an("object") - .that.has.all.keys( - scientificMetadataFieldName.keyValue, - scientificMetadataFieldName.unitAndValue, - scientificMetadataFieldName.number, - scientificMetadataFieldName.string, - ); - pid = encodeURIComponent(res.body["pid"]); - }); - }); - - it("0020: should fetch dataset with correct unitSI and ValueSI condition for scientific filter", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send( - scientificMetadata([ - { - lhs: scientificMetadataFieldName.unitAndValue, - relation: Relation.GREATER_THAN, - rhs: 99, - unit: "mbar l/s/cm^2", - }, - { - lhs: scientificMetadataFieldName.unitAndValue, - relation: Relation.EQUAL_TO_NUMERIC, - rhs: 100, - unit: "mbar l/s/cm^2", - }, - { - lhs: scientificMetadataFieldName.unitAndValue, - relation: Relation.LESS_THAN, - rhs: 101, - unit: "mbar l/s/cm^2", - }, - ]), - ) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.include(decodeURIComponent(pid)); - }); - }); - - it("0027: should fetch dataset with correct numeric value for scientific filter", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send( - scientificMetadata([ - { - lhs: scientificMetadataFieldName.number, - relation: Relation.EQUAL_TO_NUMERIC, - rhs: 111, - unit: "", - }, - ]), - ) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.include(decodeURIComponent(pid)); - }); - }); - - it("0028: should fetch dataset with correct string value for the scientific filter", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send( - scientificMetadata([ - { - lhs: scientificMetadataFieldName.string, - relation: Relation.EQUAL_TO_STRING, - rhs: "222", - unit: "", - }, - ]), - ) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.include(decodeURIComponent(pid)); - }); - }); - - it("0029: should fail when fetching dataset with incorrect relation type and value type for the scientific filter", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send( - scientificMetadata([ - { - lhs: scientificMetadataFieldName.number, - relation: Relation.EQUAL_TO_NUMERIC, - rhs: "111", - unit: "", - }, - ]), - ) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.be.length(0); - }); - }); - - it("0030: should fetching dataset with correct proposalIds and size", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send({ - proposalIds: TestData.ScientificMetadataForElasticSearch.proposalId, - size: TestData.ScientificMetadataForElasticSearch.size, - }) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.include(decodeURIComponent(pid)); - }); - }); - - it("0031: should fail fetching dataset with correct proposalIds but wrong size", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send({ - proposalIds: [TestData.ScientificMetadataForElasticSearch.proposalId], - size: faker.number.int({ min: 100000001, max: 100400000 }), - }) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.be.length(0); - }); - }); - it("0032: should fail fetching dataset with wrong proposalIds but correct size", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send({ - proposalIds: ["wrongProposalId"], - size: TestData.ScientificMetadataForElasticSearch.size, - }) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.be.length(0); - }); - }); - - it("0033: should fail fetching dataset with incorrect proposalIds and size", async () => { - return request(appUrl) - .post("/api/v3/elastic-search/search") - .send({ - proposalIds: ["wrongProposalId"], - size: faker.number.int({ min: 100000001, max: 100400000 }), - }) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulPostStatusCode) - .expect("Content-Type", /json/) - .then((res) => { - res.body.data.should.be.length(0); - }); - }); - - it("0034: should delete this raw dataset", async () => { - return request(appUrl) - .delete("/api/v3/datasets/" + pid) - .set("Accept", "application/json") - .set({ Authorization: `Bearer ${accessTokenArchiveManager}` }) - .expect(TestData.SuccessfulDeleteStatusCode) - .expect("Content-Type", /json/); - }); - }, -); diff --git a/test/MetadataKeys.js b/test/MetadataKeys.js new file mode 100644 index 000000000..c62e117f0 --- /dev/null +++ b/test/MetadataKeys.js @@ -0,0 +1,174 @@ +"use strict"; +const utils = require("./LoginUtils"); +const { TestData } = require("./TestData"); + +let accessTokenAdminIngestor = null; +let accessTokenUser1 = null; +let datasetIdPrivate = null; +let datasetIdUser1 = null; + +describe("MetadataKeys v4 ACL", () => { + before(async () => { + db.collection("MetadataKeys").deleteMany({}); + + accessTokenAdminIngestor = await utils.getToken(appUrl, { + username: "adminIngestor", + password: TestData.Accounts["adminIngestor"]["password"], + }); + + accessTokenUser1 = await utils.getToken(appUrl, { + username: "user1", + password: TestData.Accounts["user1"]["password"], + }); + }); + + it("0000: create a private dataset v3 has scientific metadata for admin", async () => { + return request(appUrl) + .post("/api/v3/Datasets") + .send(TestData.RawCorrectRandom) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect("Content-Type", /json/) + .expect(TestData.EntryCreatedStatusCode) + .then((res) => { + res.body.should.have + .property("datasetName") + .and.equal(TestData.RawCorrectRandom.datasetName); + + datasetIdPrivate = encodeURIComponent(res.body["pid"]); + }); + }); + + it("0001: create a public dataset v4 has scientific metadata for unauthenticated user", async () => { + const publicDataset = { ...TestData.RawCorrectV4, isPublished: true }; + return request(appUrl) + .post("/api/v4/Datasets") + .send(publicDataset) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect("Content-Type", /json/) + .expect(TestData.EntryCreatedStatusCode) + .then((res) => { + res.body.should.have + .property("datasetName") + .and.equal(publicDataset.datasetName); + }); + }); + + it("0002: create a private dataset v4 has scientific metadata for user1", async () => { + const user1Dataset = { ...TestData.RawCorrectV4, accessGroups: ["group1"] }; + return request(appUrl) + .post("/api/v4/Datasets") + .send(user1Dataset) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect("Content-Type", /json/) + .expect(TestData.EntryCreatedStatusCode) + .then((res) => { + res.body.should.have + .property("datasetName") + .and.equal(user1Dataset.datasetName); + + datasetIdUser1 = encodeURIComponent(res.body["pid"]); + }); + }); + + it("0010: should allow admin to list all metadata keys", async () => { + const filter = { + limits: { limit: 10, skip: 0, sort: { createdAt: "desc" } }, + }; + + return request(appUrl) + .get( + `/api/v4/metadatakeys?filter=${encodeURIComponent(JSON.stringify(filter))}`, + ) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.be.an("array").that.satisfies((arr) => { + const values = arr.map((item) => item.isPublished); + return values.includes(true) && values.includes(false); + }); + }); + }); + + it("0020: should allow unauthenticated user to list only published metadata keys", async () => { + const filter = { + where: { sourceType: "dataset" }, + limits: { limit: 10, skip: 0, sort: { createdAt: "desc" } }, + }; + + return request(appUrl) + .get( + `/api/v4/metadatakeys?filter=${encodeURIComponent(JSON.stringify(filter))}`, + ) + .set("Accept", "application/json") + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.be.an("array").that.satisfies((arr) => { + return arr.every((item) => item.isPublished === true); + }); + }); + }); + + it("0030: should allow authenticated user to list metadata keys they have access", async () => { + const filter = { limits: { limit: 1, skip: 0 } }; + + return request(appUrl) + .get( + `/api/v4/metadatakeys?filter=${encodeURIComponent(JSON.stringify(filter))}`, + ) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenUser1}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.be.an("array").that.satisfies((arr) => { + return arr.every((item) => { + return ( + item.isPublished === true || item.userGroups.includes("group1") + ); + }); + }); + }); + }); + + it("0040: should return empty array when user queries keys they don't have access to", async () => { + const filter = { + where: { sourceType: "dataset", sourceId: datasetIdPrivate }, + limits: { limit: 10, skip: 0 }, + }; + + return request(appUrl) + .get( + `/api/v4/metadatakeys?filter=${encodeURIComponent(JSON.stringify(filter))}`, + ) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenUser1}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.be.an("array").and.have.length(0); + }); + }); + + it("0040: should return metadatakeys with correct access for user1", async () => { + const filter = { + where: { sourceType: "dataset", sourceId: `${datasetIdUser1}` }, + limits: { limit: 10, skip: 0 }, + }; + + return request(appUrl) + .get(`/api/v4/metadatakeys?filter=${JSON.stringify(filter)}`) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenUser1}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.be.an("array").and.have.length.of.at.least(1); + }); + }); +}); diff --git a/test/Oauth.js b/test/Oauth.js new file mode 100644 index 000000000..536b33f81 --- /dev/null +++ b/test/Oauth.js @@ -0,0 +1,102 @@ +const { TestData } = require("./TestData"); + +const isCI = process.env.CI === "true"; + +describe("OIDC E2E", () => { + before(function () { + if (!isCI) this.skip(); + }); + + const keycloakUrl = "http://localhost:8080"; + + const testUser = { + username: "test-username", + password: "test-password", + email: "test@test.com", + }; + const tokenBody = (clientId) => { + return { + grant_type: "password", + client_id: clientId, + client_secret: clientId === "scicat-client-test" ? "secret" : undefined, + username: testUser.username, + password: testUser.password, + scope: "openid", + }; + }; + + it("should exchange scicat token from main client", async () => { + const res = await request(keycloakUrl) + .post("/local-test/token") + .type("form") + .send(tokenBody("scicat-client-test")) + .expect(TestData.EntryValidStatusCode) + .expect("Content-Type", /json/); + + // Avoid hitting rate limits + await new Promise((resolve) => setTimeout(resolve, 1000)); + + return request(appUrl) + .post("/api/v3/auth/oidc/token") + .send({ idToken: res.body.id_token }) + .set("Accept", "application/json") + .expect(TestData.EntryCreatedStatusCode) + .then((res) => res.body.user.email === testUser.email); + }); + + it("should exchange scicat token from first additional authorized client", async () => { + const res = await request(keycloakUrl) + .post("/local-test/token") + .type("form") + .send(tokenBody("additional-authorized-client-test-1")) + .expect(TestData.EntryValidStatusCode) + .expect("Content-Type", /json/); + + // Avoid hitting rate limits + await new Promise((resolve) => setTimeout(resolve, 1000)); + + return request(appUrl) + .post("/api/v3/auth/oidc/token") + .send({ idToken: res.body.id_token }) + .set("Accept", "application/json") + .expect(TestData.EntryCreatedStatusCode) + .then((res) => res.body.user.email === testUser.email); + }); + + it("should exchange scicat token from second additional authorized client", async () => { + const res = await request(keycloakUrl) + .post("/local-test/token") + .type("form") + .send(tokenBody("additional-authorized-client-test-2")) + .expect(TestData.EntryValidStatusCode) + .expect("Content-Type", /json/); + + // Avoid hitting rate limits + await new Promise((resolve) => setTimeout(resolve, 1000)); + + return request(appUrl) + .post("/api/v3/auth/oidc/token") + .send({ idToken: res.body.id_token }) + .set("Accept", "application/json") + .expect(TestData.EntryCreatedStatusCode) + .then((res) => res.body.user.email === testUser.email); + }); + + it("should reject token exchange from untrusted client", async () => { + const res = await request(keycloakUrl) + .post("/local-test/token") + .type("form") + .send(tokenBody("untrusted-client-test")) + .expect(TestData.EntryValidStatusCode) + .expect("Content-Type", /json/); + + // Avoid hitting rate limits + await new Promise((resolve) => setTimeout(resolve, 1000)); + + return request(appUrl) + .post("/api/v3/auth/oidc/token") + .send({ idToken: res.body.id_token }) + .set("Accept", "application/json") + .expect(TestData.UnauthorizedStatusCode); + }); +}); diff --git a/test/OpenSearch.js b/test/OpenSearch.js new file mode 100644 index 000000000..d8e645dad --- /dev/null +++ b/test/OpenSearch.js @@ -0,0 +1,249 @@ +"use strict"; +const { faker } = require("@faker-js/faker"); +const utils = require("./LoginUtils"); +const { TestData } = require("./TestData"); +require("dotenv").config(); + +let accessTokenAdminIngestor = null, + accessTokenArchiveManager = null, + pid1 = null, + pid2 = null; + +const commonName = "common"; + +const datasetName1 = `XRD_Si02_Beam3_2024A_thetaScan_dSpacing3.14_run07 ${commonName}`; +const datasetName2 = `Neutron_CeO2_400K_P12bar_timeOfFlight_lambda1.8_seq42 ${commonName}`; + +const datasetName1Tokens = [ + "XRD", + "Si02", + "Beam3", + "2024A", + "thetaScan", + "dSpacing3.14", + "run07", +]; +const datasetName2Tokens = [ + "Neutron", + "CeO2", + "400K", + "P12bar", + "timeOfFlight", + "lambda1.8", + "seq42", +]; + +const randomToken1 = + datasetName1Tokens[Math.floor(Math.random() * datasetName1Tokens.length)]; +const randomToken2 = + datasetName2Tokens[Math.floor(Math.random() * datasetName2Tokens.length)]; + +const isOSenabled = process.env.OPENSEARCH_ENABLED == "yes"; + +(isOSenabled ? describe : describe.skip)( + "Opensearch: CRUD, filtering and search test case", + () => { + before(async () => { + db.collection("Dataset").deleteMany({}); + + accessTokenAdminIngestor = await utils.getToken(appUrl, { + username: "adminIngestor", + password: TestData.Accounts["adminIngestor"]["password"], + }); + + accessTokenArchiveManager = await utils.getToken(appUrl, { + username: "archiveManager", + password: TestData.Accounts["archiveManager"]["password"], + }); + }); + + it("0010: adds a new raw dataset -1 ", async () => { + const dataset1 = { + ...TestData.DatasetWithScientificMetadata, + datasetName: datasetName1, + isPublished: true, + }; + + return request(appUrl) + .post("/api/v3/Datasets") + .send(dataset1) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.EntryCreatedStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + pid1 = encodeURIComponent(res.body["pid"]); + }); + }); + + it("0011: adds a new raw dataset -2 ", async () => { + const dataset2 = { + ...TestData.DatasetWithScientificMetadata, + datasetName: datasetName2, + isPublished: true, + }; + + return request(appUrl) + .post("/api/v3/Datasets") + .send(dataset2) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.EntryCreatedStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + pid2 = encodeURIComponent(res.body["pid"]); + }); + }); + + it("0020: finds the dataset1 by partial text search", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: randomToken1 }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .expect(200) + .then((res) => { + const found = res.body.some((d) => d.datasetName === datasetName1); + found.should.equal(true); + }); + }); + + it("0021: finds the dataset2 by partial text search", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: randomToken2 }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .expect(200) + .then((res) => { + const found = res.body.some((d) => d.datasetName === datasetName2); + found.should.equal(true); + }); + }); + + it("0022: finds the dataset1 by full text search", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: datasetName1 }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .expect(200) + .then((res) => { + const found = res.body.some((d) => d.datasetName === datasetName2); + found.should.equal(true); + }); + }); + + it("0023: finds the dataset2 by full text search", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: datasetName2 }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .expect(200) + .then((res) => { + const found = res.body.some((d) => d.datasetName === datasetName2); + found.should.equal(true); + }); + }); + + it("0024: finds both datasets by shared common text", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: commonName }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(200) + .then((res) => { + const foundDataset1 = res.body.some( + (d) => d.datasetName === datasetName1, + ); + const foundDataset2 = res.body.some( + (d) => d.datasetName === datasetName2, + ); + foundDataset1.should.equal(true); + foundDataset2.should.equal(true); + }); + }); + + it("0025: should finds both datasets by shared common text", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: commonName }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(200) + .then((res) => { + const foundDataset1 = res.body.some( + (d) => d.datasetName === datasetName1, + ); + const foundDataset2 = res.body.some( + (d) => d.datasetName === datasetName2, + ); + foundDataset1.should.equal(true); + foundDataset2.should.equal(true); + }); + }); + + it("0026: returns no datasets for irrelevant search text", async () => { + return request(appUrl) + .get("/api/v3/datasets/fullquery") + .query({ + fields: JSON.stringify({ text: "shouldnotmatchanything" }), + limits: JSON.stringify({ + skip: 0, + limit: 10, + }), + }) + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(200) + .then((res) => { + res.body.length.should.equal(0); + }); + }); + + it("0034: should delete dataset1", async () => { + return request(appUrl) + .delete("/api/v3/datasets/" + pid1) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenArchiveManager}` }) + .expect(TestData.SuccessfulDeleteStatusCode) + .expect("Content-Type", /json/); + }); + + it("0035: should delete dataset2", async () => { + return request(appUrl) + .delete("/api/v3/datasets/" + pid2) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenArchiveManager}` }) + .expect(TestData.SuccessfulDeleteStatusCode) + .expect("Content-Type", /json/); + }); + }, +); diff --git a/test/PublishedDataV4.js b/test/PublishedDataV4.js index 86b13aa68..131cb82db 100644 --- a/test/PublishedDataV4.js +++ b/test/PublishedDataV4.js @@ -5,7 +5,6 @@ const sandbox = require("sinon").createSandbox(); let accessTokenArchiveManager = null, accessTokenAdminIngestor = null, - idOrigDatablock = null, pid = null, pidnonpublic = null, @@ -77,6 +76,21 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", }); }); + it("0011: formpopulate should return default values for metadata", async () => { + return request(appUrl) + .get(`/api/v4/PublishedData/formpopulate?pid=${encodeURIComponent(pid)}`) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.EntryValidStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.have.property("metadata"); + res.body.metadata.should.have + .property("publicationYear") + .and.equal(new Date().getFullYear()); + }); + }); + it("0015: adds a published data", async () => { return request(appUrl) .post("/api/v4/PublishedData") @@ -103,9 +117,11 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", it("0023: should fetch all published data as admin ingestor with fields", async () => { const limits = { skip: 0 }; - const fields = { createdBy: { $regex: "admin", $options: "i" } } + const fields = { createdBy: { $regex: "admin", $options: "i" } }; return request(appUrl) - .get(`/api/v4/PublishedData?fields=${encodeURIComponent(JSON.stringify(fields))}&limits=${encodeURIComponent(JSON.stringify(limits))}`) + .get( + `/api/v4/PublishedData?fields=${encodeURIComponent(JSON.stringify(fields))}&limits=${encodeURIComponent(JSON.stringify(limits))}`, + ) .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.SuccessfulGetStatusCode) @@ -300,10 +316,10 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", return request(appUrl) .get( "/api/v3/Datasets/fullquery" + - "?fields=" + - encodeURIComponent(JSON.stringify(fields)) + - "&limits=" + - encodeURIComponent(JSON.stringify(limits)), + "?fields=" + + encodeURIComponent(JSON.stringify(fields)) + + "&limits=" + + encodeURIComponent(JSON.stringify(limits)), ) .set("Accept", "application/json") .expect(TestData.SuccessfulGetStatusCode) @@ -324,10 +340,10 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", return request(appUrl) .get( "/api/v3/Datasets/fullquery" + - "?fields=" + - encodeURIComponent(JSON.stringify(fields)) + - "&limits=" + - encodeURIComponent(JSON.stringify(limits)), + "?fields=" + + encodeURIComponent(JSON.stringify(fields)) + + "&limits=" + + encodeURIComponent(JSON.stringify(limits)), ) .set("Accept", "application/json") .expect(TestData.SuccessfulGetStatusCode) @@ -362,10 +378,10 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", return request(appUrl) .get( "/api/v3/Datasets/findOne" + - "?filter=" + - encodeURIComponent(JSON.stringify(filter)) + - "&limits=" + - encodeURIComponent(JSON.stringify(limits)), + "?filter=" + + encodeURIComponent(JSON.stringify(filter)) + + "&limits=" + + encodeURIComponent(JSON.stringify(limits)), ) .set("Accept", "application/json") .expect(TestData.SuccessfulGetStatusCode) diff --git a/test/RawDataset.js b/test/RawDataset.js index d6a93ace5..c55347b8e 100644 --- a/test/RawDataset.js +++ b/test/RawDataset.js @@ -127,6 +127,7 @@ describe("1900: RawDataset: Raw Datasets", () => { .expect("Content-Type", /json/) .then((res) => { res.body.should.have.property("valid").and.equal(false); + res.body.should.have.property("error").and.equal("principalInvestigator must be a string; creationLocation must be a string"); }); }); diff --git a/test/Sample.js b/test/Sample.js index 944acc635..d10dec2d0 100644 --- a/test/Sample.js +++ b/test/Sample.js @@ -4,10 +4,53 @@ const { TestData } = require("./TestData"); let accessTokenAdminIngestor = null, accessTokenArchiveManager = null, - sampleId = null, attachmentId = null, - datasetId = null; + datasetId = null, + sampleIdSpecial = null, + sampleIdNested = null; + +const SampleCorrectWithSpecialMetadataKeys = { + ...TestData.SampleCorrect, + sampleCharacteristics: { + "test field1": { + value: "test value", + unit: "", + }, + "test.field2": { + value: "test value", + unit: "", + }, + }, + description: "Sample with special characters in metadata keys", + ownerGroup: "group4", + accessGroups: ["group6"], +}; + +const SampleCorrectWithNestedMetadata = { + ...TestData.SampleCorrect, + sampleCharacteristics: { + "experiment test": { + "nested test1": { + value: "Test Value 1", + unit: "", + type: "string", + }, + "nested.test2": { + value: "Test Value 2", + unit: "", + type: "string", + }, + }, + regular_field: { + value: 1, + unit: "", + }, + }, + description: "Sample with nested metadata", + ownerGroup: "group4", + accessGroups: ["group6"], +}; describe("2200: Sample: Simple Sample", () => { before(async () => { @@ -216,4 +259,96 @@ describe("2200: Sample: Simple Sample", () => { .expect(TestData.SuccessfulDeleteStatusCode) .expect("Content-Type", /json/); }); + + it("0200: adds sample with special characters in metadata keys", async () => { + return request(appUrl) + .post("/api/v3/Samples") + .send(SampleCorrectWithSpecialMetadataKeys) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.EntryCreatedStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.have.property("sampleId").and.be.string; + sampleIdSpecial = res.body["sampleId"]; + }); + }); + + it("0210: retrieve sample and verify metadata keys are decoded", async () => { + return request(appUrl) + .get("/api/v3/Samples/" + sampleIdSpecial) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.have.property("sampleCharacteristics"); + res.body["sampleCharacteristics"].should.have.property("test field1"); + res.body["sampleCharacteristics"].should.have.property("test.field2"); + }); + }); + + it("0220: update sample and verify metadata keys are decoded", async () => { + const update = { + sampleCharacteristics: { + "test field1 updated": { + value: "test value", + unit: "", + }, + "test.field2.updated": { + value: "test value", + unit: "", + }, + }, + }; + return request(appUrl) + .patch("/api/v3/Samples/" + sampleIdSpecial) + .send(update) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulPatchStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.have.property("sampleCharacteristics"); + res.body["sampleCharacteristics"].should.have.property( + "test field1 updated", + ); + res.body["sampleCharacteristics"].should.have.property( + "test.field2.updated", + ); + }); + }); + + it("0230: adds sample with nested metadata keys", async () => { + return request(appUrl) + .post("/api/v3/Samples") + .send(SampleCorrectWithNestedMetadata) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.EntryCreatedStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + res.body.should.have + .property("ownerGroup") + .and.equal(SampleCorrectWithNestedMetadata.ownerGroup); + res.body.should.have.property("sampleId").and.be.string; + sampleIdNested = res.body["sampleId"]; + }); + }); + + it("0240: retrieve sample and verify nested metadata keys are decoded", async () => { + return request(appUrl) + .get("/api/v3/Samples/" + sampleIdNested) + .set("Accept", "application/json") + .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + const metadata = res.body.sampleCharacteristics; + + metadata.should.have.property("experiment test"); + metadata["experiment test"].should.have.property("nested test1"); + metadata["experiment test"].should.have.property("nested.test2"); + }); + }); }); diff --git a/test/TestData.js b/test/TestData.js index 36280b8bd..aa6a59de9 100644 --- a/test/TestData.js +++ b/test/TestData.js @@ -1,6 +1,6 @@ "use strict"; const { faker } = require("@faker-js/faker"); -const _ = require("lodash") +const _ = require("lodash"); const RawTestAccounts = require("../test/config/functionalAccounts.json"); const TestAccounts = Object.fromEntries( @@ -335,15 +335,13 @@ const TestData = { publishedOn: "JEST_ANY", retrievable: false, retrieveIntegrityCheck: false, - retrieveStatusMessage: "" + retrieveStatusMessage: "", }, description: "None, The ultimate test", endTime: "JEST_ANY", inputDatasets: [], instrumentId: "1f016ec4-7a73-11ef-ae3e-439013069377", - instrumentIds: [ - "1f016ec4-7a73-11ef-ae3e-439013069377" - ], + instrumentIds: ["1f016ec4-7a73-11ef-ae3e-439013069377"], isPublished: false, keywords: ["sls", "protein"], license: "CC BY-SA 4.0", @@ -355,20 +353,14 @@ const TestData = { ownerGroup: "p13388", packedSize: 0, pid: "JEST_ANY", - principalInvestigators: [ - "scicatingestor@your.site" - ], + principalInvestigators: ["scicatingestor@your.site"], principalInvestigator: "scicatingestor@your.site", proposalId: "JEST_ANY", - proposalIds: [ - "JEST_ANY" - ], + proposalIds: ["JEST_ANY"], relationships: [], runNumber: "123456", sampleId: "20c32b4e-7a73-11ef-9aec-5b9688aa3791i", - sampleIds: [ - "20c32b4e-7a73-11ef-9aec-5b9688aa3791i" - ], + sampleIds: ["20c32b4e-7a73-11ef-9aec-5b9688aa3791i"], scientificMetadata: { File_Prefix: "817b_B2_", approx_distance_range: { @@ -376,43 +368,43 @@ const TestData = { unit: "cm", unitSI: "m", value: [1, 2], - valueSI: [0.01, 0.02] + valueSI: [0.01, 0.02], }, approx_file_size_mb: { unit: "", - value: 8500 + value: 8500, }, beamlineParameters: { "Beam energy": { u: "eV", v: 22595, unitSI: "(kg m^2) / s^2", - valueSI: 3.6201179486175005e-15 + valueSI: 3.6201179486175005e-15, }, Monostripe: "Ru/C", "Ring current": { u: "A", v: 0.402246, unitSI: "A", - valueSI: 0.402246 - } + valueSI: 0.402246, + }, }, detectorParameters: { "Exposure time": { u: "s", v: 0.4, unitSI: "s", - valueSI: 0.4 + valueSI: 0.4, }, Objective: 20, - Scintillator: "LAG 20um" + Scintillator: "LAG 20um", }, scanParameters: { "Angular step": { u: "deg", v: 0.1, unitSI: "rad", - valueSI: 0.0017453292519943296 + valueSI: 0.0017453292519943296, }, "File Prefix": "817b_B2_", "Flat frequency": 0, @@ -425,28 +417,28 @@ const TestData = { u: "deg", v: 180, unitSI: "rad", - valueSI: 3.141592653589793 + valueSI: 3.141592653589793, }, "Rot Y min position": { u: "deg", v: 0, unitSI: "rad", - valueSI: 0 + valueSI: 0, }, "Sample In": { u: "m", v: 0, unitSI: "m", - valueSI: 0 + valueSI: 0, }, "Sample Out": { u: "m", v: -0.005, unitSI: "m", - valueSI: -0.005 + valueSI: -0.005, }, - "Sample folder": "/ramjet/817b_B2_" - } + "Sample folder": "/ramjet/817b_B2_", + }, }, sharedWith: [], size: 0, @@ -1425,7 +1417,7 @@ const TestData = { dataQualityMetrics: "test", }, - ScientificMetadataForElasticSearch: { + DatasetWithScientificMetadata: { ownerGroup: faker.company.name(), creationLocation: faker.location.city(), principalInvestigator: faker.internet.username(), @@ -1456,7 +1448,7 @@ const TestData = { }, }, - ScientificMetadataForElasticSearchV4: { + DatasetWithScientificMetadataV4: { ownerGroup: faker.company.name(), creationLocation: faker.location.city(), type: "raw", @@ -1493,10 +1485,9 @@ const TestData = { }, }; -const isEqualWithAny = (actual, expected) => +const isEqualWithAny = (actual, expected) => _.isEqualWith(actual, expected, (actualValue, expectedValue) => { - if (expectedValue === "JEST_ANY") - return true; -}); + if (expectedValue === "JEST_ANY") return true; + }); module.exports = { TestData, isEqualWithAny }; diff --git a/test/config/.env b/test/config/.env index ae29b1da9..e7b09a5ca 100644 --- a/test/config/.env +++ b/test/config/.env @@ -28,14 +28,10 @@ DOI_PREFIX="10.17199/" REGISTER_DOI_URI="https://api.test.datacite.org/dois" REGISTER_DOI_URI_V3="https://mds.test.datacite.org/doi" -ES_HOST=https://localhost:9200 -ES_USERNAME=elastic -ES_PASSWORD=duo-password -MONGODB_COLLECTION=Dataset -ES_MAX_RESULT=10000 -ES_FIELDS_LIMIT=1000 -ES_INDEX=dataset -ES_REFRESH=wait_for + +OPENSEARCH_HOST=https://localhost:9200 +OPENSEARCH_PASSWORD=Scicat_default_password_2026 +OPENSEARCH_REFRESH="wait_for" #history TRACKABLE_STRATEGY=delta diff --git a/test/jest-e2e-tests/oidc.e2e-spec.ts b/test/jest-e2e-tests/oidcSession.e2e-spec.ts similarity index 97% rename from test/jest-e2e-tests/oidc.e2e-spec.ts rename to test/jest-e2e-tests/oidcSession.e2e-spec.ts index c27619ab0..49e9b0c8f 100644 --- a/test/jest-e2e-tests/oidc.e2e-spec.ts +++ b/test/jest-e2e-tests/oidcSession.e2e-spec.ts @@ -12,7 +12,7 @@ import { TestData } from "../TestData"; import { MongoClient } from "mongodb"; ["mongo", "memory"].forEach((store) => { - describe(`OIDC test ${store}`, () => { + describe(`OIDC session test ${store}`, () => { let app: INestApplication; let mongoConnection: Connection; let mongoClient: MongoClient; diff --git a/test/jest-e2e-tests/publishedData.e2e-spec.ts b/test/jest-e2e-tests/publishedData.e2e-spec.ts index e4ab81a91..7959fca47 100644 --- a/test/jest-e2e-tests/publishedData.e2e-spec.ts +++ b/test/jest-e2e-tests/publishedData.e2e-spec.ts @@ -8,6 +8,10 @@ import request from "supertest"; import { getToken } from "../LoginUtils"; import { TestData } from "../TestData"; import { createTestingApp, createTestingModuleFactory } from "./utlis"; +import { CreateDatasetObsoleteDto } from "src/datasets/dto/create-dataset-obsolete.dto"; +import { DatasetSchema } from "src/datasets/schemas/dataset.schema"; +import { PublishedDataSchema } from "src/published-data/schemas/published-data.schema"; +import { omit } from "lodash"; describe.each([undefined, "", "https://api.test.datacite.org/dois"])( "Published data datacite test (url: %p)", @@ -18,6 +22,7 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( let httpService: HttpService; let doi: string; + let dataset: CreateDatasetObsoleteDto; beforeAll(async () => { if (registerDoiUri) { @@ -40,9 +45,19 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( }); beforeAll(async () => { + const createDatasetResponse = await request(app.getHttpServer()) + .post("/api/v3/datasets") + .send(TestData.RawCorrectMin) + .auth(token, { type: "bearer" }) + .set("Accept", "application/json") + .expect(TestData.EntryCreatedStatusCode); + dataset = createDatasetResponse.body; await request(app.getHttpServer()) .post("/api/v4/PublishedData") - .send(TestData.PublishedDataV4) + .send({ + ...TestData.PublishedDataV4, + datasetPids: [createDatasetResponse.body.pid], + }) .set("Accept", "application/json") .set({ Authorization: `Bearer ${token}` }) .expect(TestData.EntryCreatedStatusCode) @@ -53,6 +68,12 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( afterAll(async () => { if (mongoConnection.db) await mongoConnection.db.dropDatabase(); await app.close(); + + // Remove pre-save hooks added by forFeatureAsync factories to prevent + // stale closures from accumulating across describe.each iterations + for (const schema of [DatasetSchema, PublishedDataSchema]) { + schema.s.hooks._pres.get("save")?.splice(0); + } }); it("Should register this new published data", async () => { @@ -74,6 +95,21 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( .set({ Authorization: `Bearer ${token}` }) .expect(TestData.EntryCreatedStatusCode) .expect("Content-Type", /json/); + + await request(app.getHttpServer()) + .get("/api/v3/datasets/" + encodeURIComponent(dataset.pid as string)) + .auth(token, { type: "bearer" }) + .expect(TestData.SuccessfulGetStatusCode) + .expect("Content-Type", /json/) + .then((res) => { + expect(omit(res.body.datasetlifecycle, "publishedOn")).toEqual( + omit(dataset!.datasetlifecycle, "publishedOn"), + ); + expect(res.body.isPublished).toEqual(true); + expect(res.body.datasetlifecycle.publishedOn).not.toEqual( + dataset!.datasetlifecycle.publishedOn, + ); + }); }); it("Should fetch this new published data", async () => {