diff --git a/.dockerignore b/.dockerignore index 6381947a..1e140910 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,151 +1,4 @@ -# custom paths: -src/data/* -.tmp -docker/master -docker/slave -.test* -# Created by https://www.toptal.com/developers/gitignore/api/node -### Node ### -*-audit.json -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -### Node Patch ### -# Serverless Webpack directories -.webpack/ - -# Optional stylelint cache - -# SvelteKit build / generate output -.svelte-kit -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ +*.db* +/stacks +/node_modules +*.md \ No newline at end of file diff --git a/.github/DockStat-dark.png b/.github/DockStat-dark.png deleted file mode 100644 index 00ac779a..00000000 Binary files a/.github/DockStat-dark.png and /dev/null differ diff --git a/.github/workflows/build-image.yaml b/.github/workflows/build-image.yaml deleted file mode 100644 index 9d43ff17..00000000 --- a/.github/workflows/build-image.yaml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Build and Push Docker Image" - -on: - release: - types: [published] - -permissions: - packages: write - contents: read - -jobs: - build-release: - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ github.token }} - - - name: Extract version and create tag - id: get-tag - run: | - # Remove 'v' prefix from release tag if present - VERSION="${GITHUB_REF#refs/tags/v}" - # Check if pre-release and append '-pre' - if ${{ github.event.release.prerelease }}; then - TAG="$VERSION-pre" - else - TAG="$VERSION" - fi - echo "tag=$TAG" >> $GITHUB_OUTPUT - - - name: Generate Docker metadata - uses: docker/metadata-action@v5 - id: metadata - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=${{ steps.get-tag.outputs.tag }} - type=raw,value=latest,enable=${{ !github.event.release.prerelease }} - - - name: Build and push - uses: docker/build-push-action@v6 - with: - platforms: linux/amd64,linux/arm64 - context: . - file: docker/Dockerfile-base - push: true - tags: ${{ steps.metadata.outputs.tags }} - labels: ${{ steps.metadata.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/workflows/cloc.yaml b/.github/workflows/cloc.yaml deleted file mode 100644 index 0f4245f9..00000000 --- a/.github/workflows/cloc.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: "Count Lines of Code" - -permissions: - issues: write - pull-requests: write - -on: - pull_request: - branches: [main, dev] - -jobs: - cloc: - runs-on: ubuntu-24.04 - - steps: - - uses: actions/checkout@v4 - - - name: Count Lines of Code (cloc) - uses: djdefi/cloc-action@6 - with: - options: --md --report-file=cloc.md --exclude-dir=node_modules --exclude-lang=YAML,JSON --exclude-list-file=package-lock.json - - - name: Create comment from markdown file - uses: GrantBirki/comment@v2 - with: - file: cloc.md - issue-number: ${{ github.event.number }} diff --git a/.github/workflows/remove-stale.yaml b/.github/workflows/remove-stale.yaml deleted file mode 100644 index 47f9ae24..00000000 --- a/.github/workflows/remove-stale.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Close stale issues and PR" -on: - schedule: - - cron: "30 1 * * *" - -jobs: - remove-stale: - runs-on: ubuntu-24.04 - steps: - - uses: actions/stale@v9 - with: - stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days." - stale-pr-message: "This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days." - close-issue-message: "This issue was closed because it has been stalled for 5 days with no activity." - days-before-stale: 30 - days-before-close: 5 - days-before-pr-close: -1 diff --git a/.github/workflows/validation.yaml b/.github/workflows/validation.yaml deleted file mode 100644 index 9a9ec937..00000000 --- a/.github/workflows/validation.yaml +++ /dev/null @@ -1,211 +0,0 @@ -name: "CI/CD Pipeline" - -on: - push: - release: - types: [published] - -jobs: - validation: - name: "Code Validation & Tests" - runs-on: ubuntu-24.04 - permissions: - actions: read - contents: read - packages: read - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install dependencies - run: npm ci - - - name: Create varaibles.json - run: npm run local-env-file - - - name: Run code formatting - run: npm run prettier - - - name: Run linter - run: npm run lint - - - name: Build project - run: npm run build:mini - - - name: Audit packages - run: npm audit --audit-level=high - - - name: Run tests - run: npm run test:silent - - security-analysis: - name: "Security Analysis" - runs-on: ubuntu-24.04 - needs: validation - permissions: - security-events: write - contents: read - packages: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: javascript-typescript - queries: security-extended - config: | - query-filter: - - exclude: - tags: /cwe-200/ - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - - container-scanning: - name: "Container Security" - runs-on: ubuntu-24.04 - needs: validation - permissions: - security-events: write - contents: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Download Grype - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b $HOME/bin - echo "$HOME/bin" >> $GITHUB_PATH - - - name: Build Docker image - run: docker build . --file docker/Dockerfile-base --tag localbuild/testimage:latest - - - name: Run vulnerability scan - run: grype -o sarif localbuild/testimage:latest > results.sarif - - - name: Upload SARIF report - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: ./results.sarif - - build-test: - name: "Docker Build Test" - runs-on: ubuntu-24.04 - needs: validation - permissions: - contents: read - packages: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build Docker image - uses: docker/build-push-action@v6 - with: - context: . - file: docker/Dockerfile-base - platforms: linux/amd64,linux/arm64 - push: false - cache-from: type=gha - cache-to: type=gha,mode=max - - todo-management: - name: "TODO Issue Management" - runs-on: ubuntu-24.04 - needs: validation - permissions: - contents: write - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Process TODOs - uses: alstr/todo-to-issue-action@v5 - with: - INSERT_ISSUE_URLS: "true" - - - name: Commit changes - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git add -A - if [[ $(git status --porcelain) ]]; then - git commit -m "Automatically process TODOs [skip ci]" - git push - fi - - deployment: - name: "Docker Deployment" - runs-on: ubuntu-24.04 - needs: [security-analysis, container-scanning, build-test] - permissions: - packages: write - contents: read - strategy: - matrix: - include: - - type: dev - # Only enable when pushing to the dev branch - enabled: ${{ github.ref_name == 'dev' }} - - type: pre-release - # Only enable when a release event is published and it's a prerelease - enabled: ${{ github.event_name == 'release' && github.event.release.prerelease }} - - type: release - # Only enable when a release event is published and it's NOT a prerelease - enabled: ${{ github.event_name == 'release' && !github.event.release.prerelease }} - steps: - - name: Exit early if deployment is not enabled - if: ${{ !matrix.enabled }} - run: | - echo "Skipping deployment for matrix type '${{ matrix.type }}' because conditions are not met." - exit 0 - - - name: Checkout repository - if: ${{ matrix.enabled }} - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - if: ${{ matrix.enabled }} - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - if: ${{ matrix.enabled }} - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Determine tags - if: ${{ matrix.enabled }} - id: tags - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=${{ matrix.type == 'dev' && 'nightly' || matrix.type == 'pre-release' && 'pre' || matrix.type == 'release' && 'latest' }} - - - name: Build and push - if: ${{ matrix.enabled }} - uses: docker/build-push-action@v6 - with: - context: . - file: docker/Dockerfile-dev - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.tags.outputs.tags }} - labels: ${{ steps.tags.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 9e264ac0..aa426ba1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,154 +1,3 @@ -# custom paths: -src/data/* -src/data/frontendConfiguration.json - -.tmp -docker/master -docker/slave -.test* -stacks -# Created by https://www.toptal.com/developers/gitignore/api/node -### Node ### -*-audit.json -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -### Node Patch ### -# Serverless Webpack directories -.webpack/ - -# Optional stylelint cache - -# SvelteKit build / generate output -.svelte-kit -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ +*.db* +/stacks +/node_modules \ No newline at end of file diff --git a/.local-tests/stacks.md b/.local-tests/stacks.md new file mode 100644 index 00000000..4d9290cb --- /dev/null +++ b/.local-tests/stacks.md @@ -0,0 +1,39 @@ +# Testing Stacks + +## Deployment + +### Values + +- compose_spec +- name +- version +- automatic_reboot_on_error +- isCustom +- image_updates +- source +- stack_prefix + +### JSON +```json +{ + "compose_spec": { + "name": "Local Test", + "services": { + "nginx": { + "container_name": "Local-test-nginx", + "image": "dockerbogo/docker-nginx-hello-world", + "ports": [ + "8081:80" + ] + } + } + }, + "name": "Local-Test", + "version": 1, + "automatic_reboot_on_error": true, + "isCustom": true, + "image_updates": true, + "source": "Local", + "stack_prefix": "" +} +``` diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 4fd02195..00000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true \ No newline at end of file diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 209e3ef4..00000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20 diff --git a/CREDITS.md b/CREDITS.md deleted file mode 100644 index 6dd2d893..00000000 --- a/CREDITS.md +++ /dev/null @@ -1,106 +0,0 @@ -# CREDITS - -This file shows all npm packages used in DockStatAPI (also Dev packages) - -### License: (MIT AND CC-BY-3.0) - -| Name | Repository | Publisher | -| ----------------- | -------------------------------------------- | -------------------- | -| spdx-ranges@2.1.1 | https://github.com/kemitchell/spdx-ranges.js | The Linux Foundation | - -### License: Apache 2.0 - -| Name | Repository | Publisher | -| ---------------------- | ------------------------------------------ | --------- | -| qrcode-terminal@0.12.0 | https://github.com/gtanner/qrcode-terminal | N/A | - -### License: Apache-2.0 - -| Name | Repository | Publisher | -| ------------------------------------ | ------------------------------------------------------------------------ | -------------------- | -| @ampproject/remapping@2.3.0 | https://github.com/ampproject/remapping | Justin Ridgewell | -| @balena/dockerignore@1.0.2 | https://github.com/balena-io-modules/dockerignore | N/A | -| @eslint/config-array@0.19.2 | https://github.com/eslint/rewrite | Nicholas C. Zakas | -| @eslint/core@0.10.0 | https://github.com/eslint/rewrite | Nicholas C. Zakas | -| @eslint/core@0.11.0 | https://github.com/eslint/rewrite | Nicholas C. Zakas | -| @eslint/object-schema@2.1.6 | https://github.com/eslint/rewrite | Nicholas C. Zakas | -| @eslint/plugin-kit@0.2.5 | https://github.com/eslint/rewrite | Nicholas C. Zakas | -| @grpc/grpc-js@1.12.6 | https://github.com/grpc/grpc-node/tree/master/packages/grpc-js | Google Inc. | -| @grpc/proto-loader@0.7.13 | https://github.com/grpc/grpc-node | Google Inc. | -| @humanfs/core@0.19.1 | https://github.com/humanwhocodes/humanfs | Nicholas C. Zakas | -| @humanfs/node@0.16.6 | https://github.com/humanwhocodes/humanfs | Nicholas C. Zakas | -| @humanwhocodes/module-importer@1.0.1 | https://github.com/humanwhocodes/module-importer | Nicholas C. Zaks | -| @humanwhocodes/retry@0.3.1 | https://github.com/humanwhocodes/retry | Nicholas C. Zaks | -| @humanwhocodes/retry@0.4.1 | https://github.com/humanwhocodes/retry | Nicholas C. Zaks | -| @puppeteer/browsers@2.7.1 | https://github.com/puppeteer/puppeteer/tree/main/packages/browsers | The Chromium Authors | -| @scarf/scarf@1.4.0 | https://github.com/scarf-sh/scarf-js | Scarf Systems | -| @sigstore/bundle@3.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| @sigstore/core@2.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| @sigstore/protobuf-specs@0.3.3 | https://github.com/sigstore/protobuf-specs | bdehamer@github.com | -| @sigstore/sign@3.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| @sigstore/tuf@3.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| @sigstore/verify@2.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| b4a@1.6.7 | https://github.com/holepunchto/b4a | Holepunch | -| bare-events@2.5.4 | https://github.com/holepunchto/bare-events | Holepunch | -| bare-fs@4.0.1 | https://github.com/holepunchto/bare-fs | Holepunch | -| bare-os@3.4.0 | https://github.com/holepunchto/bare-os | Holepunch | -| bare-path@3.0.0 | https://github.com/holepunchto/bare-path | Holepunch | -| bare-stream@2.6.5 | https://github.com/holepunchto/bare-stream | Holepunch | -| bser@2.1.1 | https://github.com/facebook/watchman | Wez Furlong | -| chromium-bidi@1.2.0 | https://github.com/GoogleChromeLabs/chromium-bidi | The Chromium Authors | -| detect-libc@2.0.3 | https://github.com/lovell/detect-libc | Lovell Fuller | -| docker-modem@5.0.6 | https://github.com/apocas/docker-modem | Pedro Dias | -| dockerode@4.0.4 | https://github.com/apocas/dockerode | Pedro Dias | -| ejs@3.1.10 | https://github.com/mde/ejs | Matthew Eernisse | -| eslint-visitor-keys@3.4.3 | https://github.com/eslint/eslint-visitor-keys | Toru Nagashima | -| eslint-visitor-keys@4.2.0 | https://github.com/eslint/js | Toru Nagashima | -| exponential-backoff@3.1.1 | https://github.com/coveo/exponential-backoff | Sami Sayegh | -| fb-watchman@2.0.2 | https://github.com/facebook/watchman | Wez Furlong | -| filelist@1.0.4 | https://github.com/mde/filelist | Matthew Eernisse | -| human-signals@2.1.0 | https://github.com/ehmicky/human-signals | ehmicky | -| jake@10.9.2 | https://github.com/jakejs/jake | Matthew Eernisse | -| long@5.2.4 | https://github.com/dcodeIO/long.js | Daniel Wirtz | -| puppeteer-core@24.2.0 | https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core | The Chromium Authors | -| puppeteer@24.2.0 | https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer | The Chromium Authors | -| sigstore@3.0.0 | https://github.com/sigstore/sigstore-js | bdehamer@github.com | -| spdx-correct@3.2.0 | https://github.com/jslicense/spdx-correct.js | N/A | -| swagger-ui-dist@5.18.3 | https://github.com/swagger-api/swagger-ui | N/A | -| text-decoder@1.2.3 | https://github.com/holepunchto/text-decoder | Holepunch | -| tunnel-agent@0.6.0 | https://github.com/mikeal/tunnel-agent | Mikeal Rogers | -| typescript@5.7.3 | https://github.com/microsoft/TypeScript | Microsoft Corp. | -| validate-npm-package-license@3.0.4 | https://github.com/kemitchell/validate-npm-package-license.js | Kyle E. Mitchell | -| walker@1.0.8 | https://github.com/daaku/nodejs-walker | Naitik Shah | - -### License: Artistic-2.0 - -| Name | Repository | Publisher | -| ---------- | -------------------------- | ----------- | -| npm@11.1.0 | https://github.com/npm/cli | GitHub Inc. | - -### License: BlueOak-1.0.0 - -| Name | Repository | Publisher | -| ---------------------------- | ------------------------------------------------ | ------------------ | -| chownr@3.0.0 | https://github.com/isaacs/chownr | Isaac Z. Schlueter | -| jackspeak@3.4.3 | https://github.com/isaacs/jackspeak | Isaac Z. Schlueter | -| package-json-from-dist@1.0.1 | https://github.com/isaacs/package-json-from-dist | Isaac Z. Schlueter | -| path-scurry@1.11.1 | https://github.com/isaacs/path-scurry | Isaac Z. Schlueter | -| yallist@5.0.0 | https://github.com/isaacs/yallist | Isaac Z. Schlueter | - -### License: CC-BY-3.0 - -| Name | Repository | Publisher | -| --------------------- | -------------------------------------------------- | -------------------- | -| spdx-exceptions@2.5.0 | https://github.com/kemitchell/spdx-exceptions.json | The Linux Foundation | - -### License: CC-BY-4.0 - -| Name | Repository | Publisher | -| ------------------------- | -------------------------------------------- | ---------- | -| caniuse-lite@1.0.30001698 | https://github.com/browserslist/caniuse-lite | Ben Briggs | - -### License: Python-2.0 - -| Name | Repository | Publisher | -| -------------- | ---------------------------------- | --------- | -| argparse@2.0.1 | https://github.com/nodeca/argparse | N/A | diff --git a/LICENSE b/LICENSE index 1e9ecebd..428e5953 100644 --- a/LICENSE +++ b/LICENSE @@ -1,28 +1,407 @@ -BSD 3-Clause License - -Copyright (c) 2024, ItsNik - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Attribution-NonCommercial 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + j. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + k. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + l. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the "Licensor." The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md index 4fc979cf..cbb25b7a 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,72 @@ -# Deprecation Warning! -# V2 is abondend, since there where to many issues in the codebase! -# Please see v3 (next commit from this one onwards, all other branches which are not based on bun will be deleted!) +# DockStat API v3 -# DockStatAPI v2 +! WIP Documentation ! -![Dockstat Logo](.github/DockStat.png) +## Usage -
+The DockStat API provides the following endpoints: -# Pipelines +### Docker Containers +- `GET /docker/containers`: Retrieve statistics for all containers across all configured Docker hosts. -[![Docker Image CI](https://img.shields.io/github/actions/workflow/status/Its4Nik/dockstatapi/build-image.yml?branch=main&label=Docker%20Image%20CI&style=for-the-badge&logo=docker)](https://github.com/Its4Nik/dockstatapi/actions/workflows/build-image.yml) -[![Validation](https://img.shields.io/github/actions/workflow/status/Its4Nik/dockstatapi/validation.yml?branch=dev&label=Validation&style=for-the-badge&logo=checkmarx)](https://github.com/Its4Nik/dockstatapi/actions/workflows/validation.yml) +### Docker Hosts +- `GET /docker/hosts/:id`: Retrieve configuration and statistics for a specific Docker host. -
+### Docker Configuration +- `POST /docker-config/add-host`: Add a new Docker host. +- `POST /docker-config/update-host`: Update an existing Docker host. +- `GET /docker-config/hosts`: Retrieve a list of all configured Docker hosts. -This specific branch contains the currently WIP **DockStatAPI-v2**, this update will bring major breaking changes so please be careful. -With this new release a couple of extra features (compared to v1) are going to be available. +### API Configuration +- `GET /config/get`: Retrieve the current API configuration. +- `POST /config/update`: Update the API configuration. -### Feature List: +### Logs +- `GET /logs`: Retrieve all backend logs. +- `GET /logs/:level`: Retrieve logs filtered by log level. +- `DELETE /logs`: Clear all backend logs. +- `DELETE /logs/:level`: Clear logs by log level. -- Swagger API Documentation -- Database (Keeps data for 24 hours max) -- Advanced authentication using hashes and salt -- Custom TypeScript/JavaScript notification modules! (Easy to add and configure!) -- `http` API to configure the backend -- Multi-arch docker builds (using buildx github action) -- Advanced security through middlewares: rate-limiting and authentication -- Multi Arch Docker builds through docker buildx -- High Availability using single master and unlimited worker nodes! -- Dynamically created Graphs +### Websocket +- `WS(S) /docker/stats`: Retrieve the current API configuration. -# 🔗 DockStatAPI v2 Documentation +## API -_⚠️ = Deprecation warning_ +The DockStat API exposes the following endpoints: -- [Introduction](https://outline.itsnik.de/s/dockstat) +| Endpoint | Method | Description | +| --- | --- | --- | +| `/docker/containers` | `GET` | Retrieve statistics for all containers across all configured Docker hosts. | +| `/docker/hosts/:id` | `GET` | Retrieve configuration and statistics for a specific Docker host. | +| `/docker-config/add-host` | `POST` | Add a new Docker host. | +| `/docker-config/update-host` | `POST` | Update an existing Docker host. | +| `/docker-config/hosts` | `GET` | Retrieve a list of all configured Docker hosts. | +| `/config/get` | `GET` | Retrieve the current API configuration. | +| `/config/update` | `POST` | Update the API configuration. | +| `/logs` | `GET` | Retrieve all backend logs. | +| `/logs/:level` | `GET` | Retrieve logs filtered by log level. | +| `/logs` | `DELETE` | Clear all backend logs. | +| `/logs/:level` | `DELETE` | Clear logs by log level. | - - [DockstatAPI v2](https://outline.itsnik.de/s/dockstat/doc/dockstatapi-v2-XRMDKRqMIg) +## Contributing - - [API reference](https://outline.itsnik.de/s/dockstat/doc/api-reference-1PTxqx1MQ6) - - [How dependency graphs are made](https://outline.itsnik.de/s/dockstat/doc/how-the-dependecy-graphs-are-made-svuZbEHH9g) +1. Fork the repository. +2. Create a new branch for your feature or bug fix. +3. Make your changes and commit them. +4. Push your branch to your forked repository. +5. Submit a pull request to the main repository. - - [DockStat v1](https://outline.itsnik.de/s/dockstat/doc/dockstat-v1-zVaFS4zROI) +## License - - [⚠️ Customisation](https://outline.itsnik.de/s/dockstat/doc/customization-PiBz4OpQIZ) - - [⚠️ Themes](https://outline.itsnik.de/s/dockstat/doc/themes-BFhN6ZBbYx) - - [⚠️ Installation](https://outline.itsnik.de/s/dockstat/doc/installation-DaO99bB86q) +This project is licensed under the CC BY-NC 4.0 License. +![cc-by-nc-image](https://licensebuttons.net/l/by-nc/4.0/88x31.png) - - [⚠️ DockStatAPI v1](https://outline.itsnik.de/s/dockstat/doc/dockstatapi-v1-jLcVCfPNmS) - - [⚠️ Integrations](https://outline.itsnik.de/s/dockstat/doc/integrations-Agq1oL6HxF) - - [⚠️ Backend API reference](https://outline.itsnik.de/s/dockstat/doc/backend-api-reference-YzcBbDvY33) +## Testing -# Dependencies - -Please see [CREDITS.md](./CREDITS.md). - -To create the credits file use: `npm run license` - -Or if you want it as a pre-commit hook create this file: - -```bash -#!/bin/bash -# .git/hooks/pre-commit - -npm run license +To run the tests, execute the following command: +(Currently no tests configured!) +``` +bun test ``` -# DockStat(APIs) goals - -DockStack tries to be a lightweigh and more "dashboard" like then [portainer](https://github.com/portainer/portainer), [cAdvisor](https://github.com/google/cadvisor), [dockge](https://github.com/louislam/dockge), ... -I also try to add some "extensions", like in V1 with [🥤cup](https://github.com/sergi0g/cup). -Everything is configured through a backend with Swagger documentation, so that you can follow the code and understand the new v2 frontend better! -DockStat is mainly used for teaching [myself](https://github.com/Its4Nik) more about TypeScript, APIs and backend development! +This will run the test suite and report the results. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index b850ba72..00000000 --- a/TODO.md +++ /dev/null @@ -1,18 +0,0 @@ -- [x] ~Better Offline mode using "faker" library or self written (probably self written)~ Not needed since there is a docker-compsoe file for local testing integrated inside the repo -- [x] HA compatibility -- [x] !!! Needs testing !!! Add automatic notifications when container state changes, according to selected level for notification service -- [ ] Image update and update notifications -- [ ] trigger container restart / stop / start via backend routes -- [x] Add more logging -- [x] Structure code differently -- [x] Write new README and make the docs better -- [x] Update more files to correct TS syntax => remove "any" -- [x] Websockets -- [x] Better /api/status endpoint with connection status of each host -- [x] Update notification service -- [x] Adjust process.env variables since they don't really work as expected (See [commit](https://github.com/Its4Nik/dockstatapi/pull/21/commits/a03b58c7a17e269f46216df5492e18d008774961)) -- [ ] Better project structure -- [x] Update logging => Better errors -- [x] Update json responses -- [x] Swagger update -- [ ] Edge case testing diff --git a/__tests__/auth.spec.ts b/__tests__/auth.spec.ts deleted file mode 100644 index 84c5f04a..00000000 --- a/__tests__/auth.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -export const testPass = "123456789"; -import { Server } from "http"; -import supertest from "supertest"; -import { startServer } from "../src/utils/startServer"; -import app from "../src/server"; - -const port = 13001; -const server = new Server(app); - -startServer(app, server, port); - -const request = supertest(`http://localhost:${port}`); - -describe("Authentication", () => { - it("Enable Authentication", async () => { - const res = await request.post(`/auth/enable?password=${testPass}`); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - expect(res.body).toHaveProperty( - "message", - "Authentication enabled successfully", - ); - }); - - it("Test no password", async () => { - const res = await request.get("/api/status"); - expect(res.status).toEqual(403); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("Disable authentication", async () => { - const res = await request - .post(`/auth/disable?password=${testPass}`) - .set("x-password", testPass); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); -}); diff --git a/__tests__/config.spec.ts b/__tests__/config.spec.ts deleted file mode 100644 index 2650e9ed..00000000 --- a/__tests__/config.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import supertest from "supertest"; -import { startServer } from "../src/utils/startServer"; -import app from "../src/server"; -import { Server } from "http"; - -const port = 13002; -const server = new Server(app); - -startServer(app, server, port); - -const request = supertest(`http://localhost:${port}`); - -const mockServerName: string = "mockstatapi"; -const mockServerIP: string = "127.0.0.1"; -const mockServerPort: number = 2375; - -describe("Config endpoints", () => { - it("Add an host", async () => { - let res = await request.put( - `/conf/addHost?name=${mockServerName}&url=${mockServerIP}&port=${mockServerPort}`, - ); - expect(res.status).toEqual(200); - - res = await request.get("/api/hosts"); - expect(res.status).toEqual(200); - expect(res.body).toContain("mockstatapi"); - }); - - it("Adjust scheduler", async () => { - let res = await request.put("/conf/scheduler?interval=10m"); - expect(res.status).toEqual(200); - - res = await request.get("/api/current-schedule"); - expect(res.status).toEqual(200); - - // Reset to standart 5m - res = await request.put("/conf/scheduler?interval=5m"); - expect(res.status).toEqual(200); - }); - - it("Remove Host from config", async () => { - let res = await request.delete(`/conf/removeHost?hostName=mockstatapi`); - expect(res.status).toEqual(200); - - res = await request.get("/api/hosts"); - expect(res.status).toEqual(200); - expect(res.body).not.toHaveProperty("mockstatapi"); - }); -}); diff --git a/__tests__/database.spec.ts b/__tests__/database.spec.ts deleted file mode 100644 index 55102ce9..00000000 --- a/__tests__/database.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import supertest from "supertest"; -import { startServer } from "../src/utils/startServer"; -import app from "../src/server"; -import { Server } from "http"; - -const port = 13003; -const server = new Server(app); - -startServer(app, server, port); - -const request = supertest(`http://localhost:${port}`); - -describe("Database", () => { - it("Get latest database entry", async () => { - const res = await request.get("/data/latest"); - expect(res.status).toEqual(200); - }); - - it("Get all database entries", async () => { - const res = await request.get("/data/all"); - expect(res.status).toEqual(200); - }); - - it("Clear database", async () => { - let res = await request.delete("/data/clear"); - expect(res.status).toEqual(200); - - res = await request.get("/data/latest"); - expect(res.status).toEqual(404); - expect(res.body).toHaveProperty( - "message", - "No data available for /data/latest", - ); - }); -}); diff --git a/__tests__/frontend.spec.ts b/__tests__/frontend.spec.ts deleted file mode 100644 index af25adc5..00000000 --- a/__tests__/frontend.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import supertest from "supertest"; -import { startServer } from "../src/utils/startServer"; -import app from "../src/server"; -import { Server } from "http"; - -const port = 13004; -const server = new Server(app); - -startServer(app, server, port); - -const request = supertest(`http://localhost:${port}`); - -const sec: number = 1000; - -const mockContainer: string = "dockstatapi"; -const mockLink: string = "https://github.com/its4nik/dockstatapi"; -const mockIcon: string = "dockstatapi.png"; -const mockTag1: string = "backend"; -const mockTag2: string = "local"; - -const verifiedResponse = [ - { - name: "dockstatapi", - tags: ["backend", "local"], - pinned: true, - link: "https://github.com/its4nik/dockstatapi", - icon: "dockstatapi.png", - hidden: true, - }, -]; - -describe("Test frontend specific configurations", () => { - it( - "Setup the configuration file", - async () => { - // Hide container - let res = await request.delete(`/frontend/hide/${mockContainer}`); - - expect(res.status).toEqual(200); - - // Add Tag(s) - res = await request.post(`/frontend/tag/${mockContainer}/${mockTag1}`); - - expect(res.status).toEqual(200); - res = await request.post(`/frontend/tag/${mockContainer}/${mockTag2}`); - - expect(res.status).toEqual(200); - - // Pin container - res = await request.post(`/frontend/pin/${mockContainer}`); - - expect(res.status).toEqual(200); - - // Add link - res = await request.post( - `/frontend/add-link/${mockContainer}/${encodeURIComponent(mockLink)}`, - ); - - expect(res.status).toEqual(200); - - // Add icon - res = await request.post( - `/frontend/add-icon/${mockContainer}/${mockIcon}/false`, - ); - - expect(res.status).toEqual(200); - }, - 60 * sec, - ); - - it("Verify the configuration", async () => { - const res = await request.get("/api/frontend-config"); - - expect(res.status).toEqual(200); - expect(res.body).toEqual(verifiedResponse); - }); - - it( - "Reset configuration", - async () => { - // Show container - let res = await request.post(`/frontend/show/${mockContainer}`); - - expect(res.status).toEqual(200); - - // Remove tag(s) - res = await request.delete( - `/frontend/remove-tag/${mockContainer}/${mockTag1}`, - ); - - expect(res.status).toEqual(200); - - res = await request.delete( - `/frontend/remove-tag/${mockContainer}/${mockTag2}`, - ); - - expect(res.status).toEqual(200); - - // Unpin - res = await request.delete(`/frontend/unpin/${mockContainer}`); - - expect(res.status).toEqual(200); - - // Remove link - res = await request.delete(`/frontend/remove-link/${mockContainer}`); - - expect(res.status).toEqual(200); - - // Remove icon - res = await request.delete(`/frontend/remove-icon/${mockContainer}`); - - expect(res.status).toEqual(200); - }, - 60 * sec, - ); - - it("Verify the reset configuration", async () => { - const res = await request.get("/api/frontend-config"); - - expect(res.status).toEqual(200); - expect(res.body).toEqual([]); - }); -}); diff --git a/__tests__/getters.spec.ts b/__tests__/getters.spec.ts deleted file mode 100644 index f951f42a..00000000 --- a/__tests__/getters.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { createPreviousResponse } from "./util/previousResponse"; -import supertest from "supertest"; -import { startServer } from "../src/utils/startServer"; -import app from "../src/server"; -import { Server } from "http"; - -const port = 13005; -const server = new Server(app); - -startServer(app, server, port); - -const request = supertest(`http://localhost:${port}`); -const PreviousResponse = createPreviousResponse(); - -describe("Get endpoints", () => { - it("GET /api/hosts", async () => { - const res = await request.get("/api/hosts"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - - const hosts: string[] = res.body; - - if (hosts.length >= 1) { - expect(Array.isArray(hosts)).toBe(true); - expect(hosts.length).toBeGreaterThan(0); - expect(typeof hosts[0]).toBe("string"); - PreviousResponse.set(hosts[0]); - } - }); - - it("GET /api/host/:host/stats", async () => { - const host = PreviousResponse.get(); - - if (!host) { - console.log("No hosts found, skipping /api/host/:host/stats test"); - return; - } - - const res = await request.get(`/api/host/${host}/stats`); - - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("GET /api/system", async () => { - const res = await request.get("/api/system"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("GET /api/status", async () => { - const res = await request.get("/api/status"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - expect(res.body).toHaveProperty("ApiReachable", true); - }); - - it("GET /api/containers", async () => { - const res = await request.get("/api/containers"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("GET /api/config", async () => { - const res = await request.get("/api/config"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - expect(res.body).toHaveProperty("hosts"); - }); - - it("GET /api/current-schedule", async () => { - const res = await request.get("/api/current-schedule"); - - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - expect(res.body).toHaveProperty("interval"); - }); - - it("GET /api/frontend-config", async () => { - const res = await request.get("/api/frontend-config"); - - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("GET /ha/config", async () => { - const res = await request.get("/ha/config"); - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - }); - - it("GET /notification-service/get-template", async () => { - const res = await request.get("/notification-service/get-template"); - - expect(res.status).toEqual(200); - expect(res.type).toEqual(expect.stringContaining("json")); - expect(res.body).toHaveProperty("text"); - }); -}); diff --git a/__tests__/util/previousResponse.ts b/__tests__/util/previousResponse.ts deleted file mode 100644 index 774a862a..00000000 --- a/__tests__/util/previousResponse.ts +++ /dev/null @@ -1,23 +0,0 @@ -let response: string = ""; - -class PreviousResponse { - set(body: unknown): void { - try { - response = JSON.stringify(body).replace(/[" ]/g, ""); - } catch (error: unknown) { - console.error("Error in setting response:", error); - throw new Error("Failed to set response"); - } - } - - get(): string { - try { - return response; - } catch (error: unknown) { - console.error("Error in getting response:", error); - throw new Error("Failed to get response"); - } - } -} - -export const createPreviousResponse = () => new PreviousResponse(); diff --git a/bun.lock b/bun.lock new file mode 100644 index 00000000..f91ae698 --- /dev/null +++ b/bun.lock @@ -0,0 +1,311 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "dockstatapi", + "dependencies": { + "@elysiajs/static": "^1.2.0", + "@elysiajs/swagger": "^1.2.2", + "chalk": "^5.4.1", + "docker-compose": "^1.1.1", + "dockerode": "^4.0.4", + "elysia": "latest", + "split2": "^4.2.0", + "winston": "^3.17.0", + "winston-transport": "^4.9.0", + "yaml": "^2.7.0", + }, + "devDependencies": { + "@types/dockerode": "^3.3.34", + "@types/split2": "^4.2.3", + "bun-types": "latest", + "cross-env": "^7.0.3", + "wrap-ansi": "^9.0.0", + }, + }, + }, + "trustedDependencies": [ + "protobufjs", + ], + "packages": { + "@balena/dockerignore": ["@balena/dockerignore@1.0.2", "", {}, "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q=="], + + "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], + + "@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="], + + "@elysiajs/static": ["@elysiajs/static@1.2.0", "", { "dependencies": { "node-cache": "^5.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-oLpAi8c+maPpA0XhhK3BELaIjIG+nXg/K9p8cFfW4q5ayRD59a3MOMOOGgpiXZkHJzLPWcouhhyyLAYtaANW4g=="], + + "@elysiajs/swagger": ["@elysiajs/swagger@1.2.2", "", { "dependencies": { "@scalar/themes": "^0.9.52", "@scalar/types": "^0.0.12", "openapi-types": "^12.1.3", "pathe": "^1.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-DG0PbX/wzQNQ6kIpFFPCvmkkWTIbNWDS7lVLv3Puy6ONklF14B4NnbDfpYjX1hdSYKeCqKBBOuenh6jKm8tbYA=="], + + "@grpc/grpc-js": ["@grpc/grpc-js@1.12.6", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q=="], + + "@grpc/proto-loader": ["@grpc/proto-loader@0.7.13", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw=="], + + "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + + "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + + "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + + "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + + "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + + "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + + "@scalar/openapi-types": ["@scalar/openapi-types@0.1.1", "", {}, "sha512-NMy3QNk6ytcCoPUGJH0t4NNr36OWXgZhA3ormr3TvhX1NDgoF95wFyodGVH8xiHeUyn2/FxtETm8UBLbB5xEmg=="], + + "@scalar/themes": ["@scalar/themes@0.9.68", "", { "dependencies": { "@scalar/types": "0.0.34" } }, "sha512-466ac2fdQJOBBSLkGUf88vuZVF+qNMeVpjb0aAHrKkxhpjucTPKdTYO8r2dsX1R5k9A13gWPnm594VW5G/bGHw=="], + + "@scalar/types": ["@scalar/types@0.0.12", "", { "dependencies": { "@scalar/openapi-types": "0.1.1", "@unhead/schema": "^1.9.5" } }, "sha512-XYZ36lSEx87i4gDqopQlGCOkdIITHHEvgkuJFrXFATQs9zHARop0PN0g4RZYWj+ZpCUclOcaOjbCt8JGe22mnQ=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.27", "", {}, "sha512-C7mxE1VC3WC2McOufZXEU48IfRVI+BcKxk4NOyNn3+JMUNdJHEWGS5CqjuDX+ij2NCCz8/nse1mT7yn8Fv2GHg=="], + + "@types/docker-modem": ["@types/docker-modem@3.0.6", "", { "dependencies": { "@types/node": "*", "@types/ssh2": "*" } }, "sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg=="], + + "@types/dockerode": ["@types/dockerode@3.3.34", "", { "dependencies": { "@types/docker-modem": "*", "@types/node": "*", "@types/ssh2": "*" } }, "sha512-mH9SuIb8NuTDsMus5epcbTzSbEo52fKLBMo0zapzYIAIyfDqoIFn7L3trekHLKC8qmxGV++pPUP4YqQ9n5v2Zg=="], + + "@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="], + + "@types/split2": ["@types/split2@4.2.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-59OXIlfUsi2k++H6CHgUQKEb2HKRokUA39HY1i1dS8/AIcqVjtAAFdf8u+HxTWK/4FUHMJQlKSZ4I6irCBJ1Zw=="], + + "@types/ssh2": ["@types/ssh2@1.15.4", "", { "dependencies": { "@types/node": "^18.11.18" } }, "sha512-9JTQgVBWSgq6mAen6PVnrAmty1lqgCMvpfN+1Ck5WRUsyMYPa6qd50/vMJ0y1zkGpOEgLzm8m8Dx/Y5vRouLaA=="], + + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], + + "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], + + "@unhead/schema": ["@unhead/schema@1.11.19", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-7VhYHWK7xHgljdv+C01MepCSYZO2v6OhgsfKWPxRQBDDGfUKCUaChox0XMq3tFvXP6u4zSp6yzcDw2yxCfVMwg=="], + + "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + + "ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + + "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], + + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="], + + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buildcheck": ["buildcheck@0.0.6", "", {}, "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A=="], + + "bun-types": ["bun-types@1.2.3", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-P7AeyTseLKAvgaZqQrvp3RqFM3yN9PlcLuSTe7SoJOfZkER73mLdT2vEQi8U64S1YvM/ldcNiQjn0Sn7H9lGgg=="], + + "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], + + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], + + "color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="], + + "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + + "colorspace": ["colorspace@1.1.4", "", { "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" } }, "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w=="], + + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "cpu-features": ["cpu-features@0.0.10", "", { "dependencies": { "buildcheck": "~0.0.6", "nan": "^2.19.0" } }, "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA=="], + + "cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "docker-compose": ["docker-compose@1.1.1", "", { "dependencies": { "yaml": "^2.2.2" } }, "sha512-UkIUz0LtzuO17Ijm6SXMGtfZMs7IvbNwvuJBiBuN93PIhr/n9/sbJMqpvYFaCBGfwu1ZM4PPPDgQzeeke4lEoA=="], + + "docker-modem": ["docker-modem@5.0.6", "", { "dependencies": { "debug": "^4.1.1", "readable-stream": "^3.5.0", "split-ca": "^1.0.1", "ssh2": "^1.15.0" } }, "sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ=="], + + "dockerode": ["dockerode@4.0.4", "", { "dependencies": { "@balena/dockerignore": "^1.0.2", "@grpc/grpc-js": "^1.11.1", "@grpc/proto-loader": "^0.7.13", "docker-modem": "^5.0.6", "protobufjs": "^7.3.2", "tar-fs": "~2.0.1", "uuid": "^10.0.0" } }, "sha512-6GYP/EdzEY50HaOxTVTJ2p+mB5xDHTMJhS+UoGrVyS6VC+iQRh7kZ4FRpUYq6nziby7hPqWhOrFFUFTMUZJJ5w=="], + + "elysia": ["elysia@1.2.21", "", { "dependencies": { "@sinclair/typebox": "^0.34.27", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-E9b1JcB7fiQ2ptk24W8OnBrMYUoKzffIXob9uTVUKhqOKxaXAd9UyWBeyr7JCDa/VD/b/9S8aIey9/YJsK5sLg=="], + + "emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], + + "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], + + "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], + + "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], + + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], + + "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], + + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + + "logform": ["logform@2.7.0", "", { "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" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], + + "long": ["long@5.3.1", "", {}, "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng=="], + + "memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="], + + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nan": ["nan@2.22.1", "", {}, "sha512-pfRR4ZcNTSm2ZFHaztuvbICf+hyiG6ecA06SfAxoPmuHjvMu0KUIae7Y8GyVkbBqeEIidsmXeYooWIX9+qjfRQ=="], + + "node-cache": ["node-cache@5.1.2", "", { "dependencies": { "clone": "2.x" } }, "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], + + "protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="], + + "pump": ["pump@3.0.2", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw=="], + + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], + + "split-ca": ["split-ca@1.0.1", "", {}, "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "ssh2": ["ssh2@1.16.0", "", { "dependencies": { "asn1": "^0.2.6", "bcrypt-pbkdf": "^1.0.2" }, "optionalDependencies": { "cpu-features": "~0.0.10", "nan": "^2.20.0" } }, "sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg=="], + + "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + + "tar-fs": ["tar-fs@2.0.1", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.0.0" } }, "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA=="], + + "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + + "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], + + "triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="], + + "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="], + + "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], + + "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "winston": ["winston@3.17.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw=="], + + "winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="], + + "wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="], + + "@scalar/themes/@scalar/types": ["@scalar/types@0.0.34", "", { "dependencies": { "@scalar/openapi-types": "0.1.8", "@unhead/schema": "^1.11.11" } }, "sha512-q01ctijmHArM5KOny2zU+sHfhpsgOAENrDENecK2TsQNn5FYLmFZouMKeW2M6F7KFLPZnFxUiL/rT88b6Rp/Kg=="], + + "@types/ssh2/@types/node": ["@types/node@18.19.76", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-yvR7Q9LdPz2vGpmpJX5LolrgRdWvB67MJKDPSgIIzpFbaf9a1j/f5DnLp5VDyHGMR0QZHlTr1afsD87QCXFHKw=="], + + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.1.8", "", {}, "sha512-iufA5/6hPCmRIVD2eh7qGpoKvoA08Gw/qUb2JECifBtAwA93fo7+1k9uHK440f2LMJsbxIzA+nv7RS0BmfiO/g=="], + + "@types/ssh2/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], + + "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + } +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..fdd42344 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,3 @@ +FROM oven/bun AS base + +WORKDIR /base diff --git a/docker/Dockerfile-base b/docker/Dockerfile-base deleted file mode 100644 index f21146ba..00000000 --- a/docker/Dockerfile-base +++ /dev/null @@ -1,76 +0,0 @@ -# Stage 1: Build stage -FROM node:20-alpine AS builder - -LABEL maintainer="https://github.com/its4nik" -LABEL version="2.0.1" -LABEL description="API for DockStat" -LABEL license="BSD-3-Clause license" -LABEL repository="https://github.com/its4nik/dockstatapi" -LABEL documentation="https://github.com/its4nik/dockstatapi" -LABEL org.opencontainers.image.description="The DockSatAPI is a free and OpenSource backend for gathering container statistics across hosts" -LABEL org.opencontainers.image.licenses="BSD-3-Clause license" -LABEL org.opencontainers.image.source="https://github.com/its4nik/dockstatapi" - -WORKDIR /app - -ENV NODE_NO_WARNINGS=1 - -RUN apk add --no-cache curl bash - -COPY package*.json tsconfig.json environment.d.ts ./ - -RUN npm ci --include=dev - -COPY ./src ./src -RUN mv ./src/sample-variable.json ./src/data/variables.json - -RUN npm run build:mini - -# -------------------------------------- -# Stage 2: Dependency pruning stage -FROM node:20-alpine AS deps -WORKDIR /api -COPY --from=builder /app/package*.json . -RUN npm ci --omit=dev - -# -------------------------------------- -# Stage 3: Final production image -FROM node:20-alpine AS prod - -WORKDIR /api - -RUN apk add --no-cache docker-cli bash curl && \ - mkdir -p /usr/libexec/docker/cli-plugins && \ - curl -sSL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" \ - -o /usr/libexec/docker/cli-plugins/docker-compose && \ - chmod +x /usr/libexec/docker/cli-plugins/docker-compose && \ - rm -rf /var/cache/apk/* - -ARG USER_ID=10001 -ARG GROUP_ID=10001 -RUN addgroup -g $GROUP_ID dockstatapi && \ - adduser -u $USER_ID -G dockstatapi -h /api -s /bin/sh -D dockstatapi - -COPY --from=builder --chown=dockstatapi:dockstatapi /app/dist/src ./src -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/config/swagger.yaml ./src/config/swagger.yaml -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/utils/assets ./src/utils/assets -COPY --from=builder /app/package.json ./ -COPY --from=deps --chown=dockstatapi:dockstatapi /api/node_modules ./node_modules - -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/misc/entrypoint.sh . -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/misc/createEnvFile.sh . -RUN chmod +x *.sh - -RUN mkdir -p /api/src/data && \ - chown -R dockstatapi:dockstatapi /api && \ - chmod -R 755 /api && \ - chmod 775 /api/src/data - -HEALTHCHECK --interval=5m --timeout=3s \ - CMD curl -f http://localhost:9876/api/status || exit 1 - -EXPOSE 9876 -STOPSIGNAL 130 -USER dockstatapi - -ENTRYPOINT [ "sh", "./entrypoint.sh", "--prod" ] diff --git a/docker/Dockerfile-dev b/docker/Dockerfile-dev deleted file mode 100644 index 00b88008..00000000 --- a/docker/Dockerfile-dev +++ /dev/null @@ -1,76 +0,0 @@ -# Stage 1: Build stage -FROM node:20-alpine AS builder - -LABEL maintainer="https://github.com/its4nik" -LABEL version="2.0.1" -LABEL description="API for DockStat" -LABEL license="BSD-3-Clause license" -LABEL repository="https://github.com/its4nik/dockstatapi" -LABEL documentation="https://github.com/its4nik/dockstatapi" -LABEL org.opencontainers.image.description="The DockSatAPI is a free and OpenSource backend for gathering container statistics across hosts" -LABEL org.opencontainers.image.licenses="BSD-3-Clause license" -LABEL org.opencontainers.image.source="https://github.com/its4nik/dockstatapi" - -WORKDIR /app - -ENV NODE_NO_WARNINGS=1 - -RUN apk add --no-cache curl bash - -COPY package*.json tsconfig.json environment.d.ts ./ - -RUN npm ci --include=dev - -COPY ./src ./src -RUN mv ./src/sample-variable.json ./src/data/variables.json - -RUN npm run build - -# -------------------------------------- -# Stage 2: Dependency pruning stage -FROM node:20-alpine AS deps -WORKDIR /api -COPY --from=builder /app/package*.json . -RUN npm ci --omit=dev - -# -------------------------------------- -# Stage 3: Final production image -FROM node:20-alpine AS prod - -WORKDIR /api - -RUN apk add --no-cache docker-cli bash curl && \ - mkdir -p /usr/libexec/docker/cli-plugins && \ - curl -sSL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" \ - -o /usr/libexec/docker/cli-plugins/docker-compose && \ - chmod +x /usr/libexec/docker/cli-plugins/docker-compose && \ - rm -rf /var/cache/apk/* - -ARG USER_ID=10001 -ARG GROUP_ID=10001 -RUN addgroup -g $GROUP_ID dockstatapi && \ - adduser -u $USER_ID -G dockstatapi -h /api -s /bin/sh -D dockstatapi - -COPY --from=builder --chown=dockstatapi:dockstatapi /app/dist/src ./src -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/config/swagger.yaml ./src/config/swagger.yaml -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/utils/assets ./src/utils/assets -COPY --from=builder /app/package.json ./ -COPY --from=deps --chown=dockstatapi:dockstatapi /api/node_modules ./node_modules - -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/misc/entrypoint.sh . -COPY --from=builder --chown=dockstatapi:dockstatapi /app/src/misc/createEnvFile.sh . -RUN chmod +x *.sh - -RUN mkdir -p /api/src/data && \ - chown -R dockstatapi:dockstatapi /api && \ - chmod -R 755 /api && \ - chmod 775 /api/src/data - -HEALTHCHECK --interval=5m --timeout=3s \ - CMD curl -f http://localhost:9876/api/status || exit 1 - -EXPOSE 9876 -STOPSIGNAL 130 -USER dockstatapi - -ENTRYPOINT [ "sh", "./entrypoint.sh", "--dev" ] diff --git a/docker/docker-compose.dev.yaml b/docker/docker-compose.dev.yaml index 7bc3773f..39da6d6b 100644 --- a/docker/docker-compose.dev.yaml +++ b/docker/docker-compose.dev.yaml @@ -1,40 +1,52 @@ +name: "DockStatAPI - Dev" services: - test-socket-proxy: + socket-proxy: + container_name: Socket-Proxy image: lscr.io/linuxserver/socket-proxy:latest - container_name: test-socket-proxy + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + restart: unless-stopped + read_only: true + tmpfs: + - /run + ports: + - 2375:2375 environment: - ALLOW_START=1 #optional - ALLOW_STOP=1 #optional - ALLOW_RESTARTS=1 #optional - - AUTH=0 #optional - - BUILD=0 #optional - - COMMIT=0 #optional - - CONFIGS=0 #optional + - AUTH=1 #optional + - BUILD=1 #optional + - COMMIT=1 #optional + - CONFIGS=1 #optional - CONTAINERS=1 #optional - - DISABLE_IPV6=0 #optional - - DISTRIBUTION=0 #optional + - DISABLE_IPV6=1 #optional + - DISTRIBUTION=1 #optional - EVENTS=1 #optional - - EXEC=0 #optional - - IMAGES=0 #optional + - EXEC=1 #optional + - IMAGES=1 #optional - INFO=1 #optional - NETWORKS=1 #optional - NODES=1 #optional - PING=1 #optional - - POST=0 #optional - - PLUGINS=0 #optional - - SECRETS=0 #optional - - SERVICES=0 #optional - - SESSION=0 #optional - - SWARM=0 #optional - - SYSTEM=0 #optional - - TASKS=0 #optional + - PLUGINS=1 #optional + - POST=1 #optional + - PROXY_READ_TIMEOUT=240 #optional + - SECRETS=1 #optional + - SERVICES=1 #optional + - SESSION=1 #optional + - SWARM=1 #optional + - SYSTEM=1 #optional + - TASKS=1 #optional - VERSION=1 #optional - - VOLUMES=0 #optional - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - restart: unless-stopped - read_only: true - tmpfs: - - /run + - VOLUMES=1 #optional + + sqlite-web: + container_name: SQLite-web + image: ghcr.io/coleifer/sqlite-web:latest ports: - - 2375:2375 \ No newline at end of file + - 8080:8080 + volumes: + - ../:/data:ro + environment: + - SQLITE_DATABASE=dockstatapi.db diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml deleted file mode 100644 index 436d8a21..00000000 --- a/docker/docker-compose.yaml +++ /dev/null @@ -1,82 +0,0 @@ -networks: - shared-network: - driver: bridge - -services: - master: - container_name: master - user: "${UID:-1000}:${GID:-1000}" - environment: - - NODE_ENV=development - - HA_MASTER=true - - HA_MASTER_IP=master:9876 - - HA_NODE=slave:9876 - - HA_UNSAFE=true - volumes: - - ./master/data:/api/src/data - - ./master/logs:/api/logs - ports: - - 9876:9876 - image: dockstatapi:local - networks: - - shared-network - depends_on: - - slave - - test-socket-proxy - - slave: - container_name: slave - user: "${UID:-1000}:${GID:-1000}" - environment: - - NODE_ENV=development - volumes: - - ./slave/data:/api/src/data - - ./slave/logs:/api/logs - ports: - - 6789:9876 - image: dockstatapi:local - depends_on: - - test-socket-proxy - networks: - - shared-network - - test-socket-proxy: - image: lscr.io/linuxserver/socket-proxy:latest - container_name: test-socket-proxy - environment: - - ALLOW_START=1 #optional - - ALLOW_STOP=1 #optional - - ALLOW_RESTARTS=1 #optional - - AUTH=0 #optional - - BUILD=0 #optional - - COMMIT=0 #optional - - CONFIGS=0 #optional - - CONTAINERS=1 #optional - - DISABLE_IPV6=0 #optional - - DISTRIBUTION=0 #optional - - EVENTS=1 #optional - - EXEC=0 #optional - - IMAGES=0 #optional - - INFO=1 #optional - - NETWORKS=1 #optional - - NODES=1 #optional - - PING=1 #optional - - POST=0 #optional - - PLUGINS=0 #optional - - SECRETS=0 #optional - - SERVICES=0 #optional - - SESSION=0 #optional - - SWARM=0 #optional - - SYSTEM=0 #optional - - TASKS=0 #optional - - VERSION=1 #optional - - VOLUMES=0 #optional - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - restart: unless-stopped - read_only: true - tmpfs: - - /run - networks: - - shared-network - diff --git a/environment.d.ts b/environment.d.ts deleted file mode 100644 index df2595f5..00000000 --- a/environment.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -declare global { - namespace NodeJS { - interface ProcessEnv { - // Node specific: - NODE_ENV: "development" | "production" | "testing"; - PORT: string | undefined; - CI: "true" | null; - } - } -} - -export {}; diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 56994a62..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import globals from "globals"; -import pluginJs from "@eslint/js"; -import tseslint from "typescript-eslint"; - -/** @type {import('eslint').Linter.Config[]} */ -export default [ - { ignores: ["node_modules/*", "dist/*"] }, - { files: ["src/**/*.ts"] }, - { languageOptions: { globals: globals.node } }, - pluginJs.configs.recommended, - ...tseslint.configs.recommended, -]; diff --git a/nodemon.json b/nodemon.json deleted file mode 100644 index be32c75d..00000000 --- a/nodemon.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "ignore": [ - "**/data/**", - "src/logs", - "**/fixtures/**", - ".gitignore", - "**/*.json", - "**/__tests__/**" - ], - "execMap": { - "ts": "tsx" - }, - "delay": 2500 -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 6efc7ed3..00000000 --- a/package-lock.json +++ /dev/null @@ -1,13317 +0,0 @@ -{ - "name": "dockstatapi", - "version": "2.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dockstatapi", - "version": "2.0.1", - "license": "BSD 3-Clause License", - "dependencies": { - "bcrypt": "^5.1.1", - "chokidar": "^4.0.1", - "cors": "^2.8.5", - "cytoscape": "^3.30.4", - "docker-compose": "^1.1.0", - "dockerode": "^4.0.2", - "express": "^4.21.1", - "express-rate-limit": "^7.4.1", - "https": "^1.0.0", - "i": "^0.3.7", - "ipaddr.js": "^2.2.0", - "nodemailer": "^6.9.16", - "npm": "^11.0.0", - "puppeteer": "^24.0.0", - "sqlite3": "^5.1.7", - "swagger-ui-express": "^5.0.1", - "winston": "^3.15.0", - "winston-daily-rotate-file": "^5.0.0", - "yamljs": "^0.3.0" - }, - "devDependencies": { - "@eslint/js": "^9.17.0", - "@types/bcrypt": "^5.0.2", - "@types/cors": "^2.8.17", - "@types/cytoscape": "^3.21.8", - "@types/dockerode": "^3.3.31", - "@types/express": "^5.0.0", - "@types/express-handlebars": "^5.3.1", - "@types/jest": "^29.5.14", - "@types/node": "^22.9.0", - "@types/node-fetch": "^2.6.12", - "@types/nodemailer": "^6.4.17", - "@types/supertest": "^6.0.2", - "@types/supports-color": "^8.1.3", - "@types/swagger-jsdoc": "^6.0.4", - "@types/swagger-ui-express": "^4.1.7", - "@types/ws": "^8.5.14", - "@types/yamljs": "^0.2.34", - "@typescript-eslint/eslint-plugin": "^8.18.2", - "@typescript-eslint/parser": "^8.18.2", - "dependency-cruiser": "^16.5.0", - "eslint": "^9.17.0", - "globals": "^15.14.0", - "jest": "^29.7.0", - "license-checker": "^25.0.1", - "nodemon": "^3.1.7", - "prettier": "^3.4.2", - "supertest": "^7.0.0", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2", - "tsx": "^4.19.2", - "typescript-eslint": "^8.18.2", - "uglify-js": "^3.19.3" - }, - "engines": { - "npm": ">=10.8.2" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", - "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz", - "integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.7", - "@babel/parser": "^7.26.7", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.26.7", - "@babel/types": "^7.26.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", - "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.5", - "@babel/types": "^7.26.5", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", - "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", - "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", - "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.7", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", - "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@balena/dockerignore": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", - "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", - "license": "Apache-2.0" - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@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": ">=0.1.90" - } - }, - "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": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "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/@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_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/core": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", - "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/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/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.20.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", - "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", - "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.10.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", - "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "license": "MIT", - "optional": true - }, - "node_modules/@grpc/grpc-js": { - "version": "1.12.6", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.6.tgz", - "integrity": "sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "license": "Apache-2.0", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@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==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "license": "BSD-3-Clause", - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "MIT", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" - }, - "node_modules/@puppeteer/browsers": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.7.1.tgz", - "integrity": "sha512-MK7rtm8JjaxPN7Mf1JdZIZKPD2Z+W7osvrC1vjpvfOX1K0awDIHYbNi89f7eotp7eMUn2shWnt03HwVbriXtKQ==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.4.0", - "extract-zip": "^2.0.1", - "progress": "^2.0.3", - "proxy-agent": "^6.5.0", - "semver": "^7.7.0", - "tar-fs": "^3.0.8", - "yargs": "^17.7.2" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@puppeteer/browsers/node_modules/tar-fs": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", - "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" - } - }, - "node_modules/@puppeteer/browsers/node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true, - "license": "Apache-2.0" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "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": "MIT" - }, - "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": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/bcrypt": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", - "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "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": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cytoscape": { - "version": "3.21.9", - "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.9.tgz", - "integrity": "sha512-JyrG4tllI6jvuISPjHK9j2Xv/LTbnLekLke5otGStjFluIyA9JjgnvgZrSBsp8cEDpiTjwgZUZwpPv8TSBcoLw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/docker-modem": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.6.tgz", - "integrity": "sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/ssh2": "*" - } - }, - "node_modules/@types/dockerode": { - "version": "3.3.34", - "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.34.tgz", - "integrity": "sha512-mH9SuIb8NuTDsMus5epcbTzSbEo52fKLBMo0zapzYIAIyfDqoIFn7L3trekHLKC8qmxGV++pPUP4YqQ9n5v2Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/docker-modem": "*", - "@types/node": "*", - "@types/ssh2": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", - "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-handlebars": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@types/express-handlebars/-/express-handlebars-5.3.1.tgz", - "integrity": "sha512-DSzaERLO4gHb8AqnrL58jzSDyT0yDdl6HqDc+bGz1Hf0nrG1FK30nHGzv8NBEGR8QV9eUGB/YaE0Qj3NjF7siw==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "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, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/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": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.13.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", - "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/nodemailer": { - "version": "6.4.17", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz", - "integrity": "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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, - "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/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@types/ssh2": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.4.tgz", - "integrity": "sha512-9JTQgVBWSgq6mAen6PVnrAmty1lqgCMvpfN+1Ck5WRUsyMYPa6qd50/vMJ0y1zkGpOEgLzm8m8Dx/Y5vRouLaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^18.11.18" - } - }, - "node_modules/@types/ssh2/node_modules/@types/node": { - "version": "18.19.75", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.75.tgz", - "integrity": "sha512-UIksWtThob6ZVSyxcOqCLOUNg/dyO1Qvx4McgeuhrEtHTLFTf7BBhEazaE4K806FGTPtzd/2sE90qn4fVr7cyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/ssh2/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, - "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/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/supertest": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.2.tgz", - "integrity": "sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/methods": "^1.1.4", - "@types/superagent": "^8.1.0" - } - }, - "node_modules/@types/supports-color": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.3.tgz", - "integrity": "sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/swagger-jsdoc": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz", - "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/swagger-ui-express": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.7.tgz", - "integrity": "sha512-ovLM9dNincXkzH4YwyYpll75vhzPBlWx6La89wwvYH7mHjVpf0X0K/vR/aUM7SRxmr5tt9z7E5XJcjQ46q+S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*", - "@types/serve-static": "*" - } - }, - "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/ws": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", - "integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yamljs": { - "version": "0.2.34", - "resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.34.tgz", - "integrity": "sha512-gJvfRlv9ErxdOv7ux7UsJVePtX54NAvQyd8ncoiFqK8G5aeHIfQfGH2fbruvjAQ9657HwAaO54waS+Dsk2QTUQ==", - "dev": true, - "license": "MIT" - }, - "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, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz", - "integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/type-utils": "8.23.0", - "@typescript-eslint/utils": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz", - "integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/typescript-estree": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz", - "integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz", - "integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.23.0", - "@typescript-eslint/utils": "8.23.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", - "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", - "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.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", - "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz", - "integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/typescript-estree": "8.23.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 <5.8.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", - "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.23.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-jsx-walk": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/acorn-jsx-walk/-/acorn-jsx-walk-2.0.0.tgz", - "integrity": "sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA==", - "dev": true, - "license": "MIT" - }, - "node_modules/acorn-loose": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.4.0.tgz", - "integrity": "sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.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==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", - "optional": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "license": "ISC" - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "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==", - "license": "Python-2.0" - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": 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" - } - }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", - "license": "Apache-2.0" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", - "license": "Apache-2.0", - "optional": true - }, - "node_modules/bare-fs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.1.tgz", - "integrity": "sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^3.0.0", - "bare-stream": "^2.0.0" - }, - "engines": { - "bare": ">=1.7.0" - } - }, - "node_modules/bare-os": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.4.0.tgz", - "integrity": "sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "bare": ">=1.6.0" - } - }, - "node_modules/bare-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-os": "^3.0.1" - } - }, - "node_modules/bare-stream": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", - "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "streamx": "^2.21.0" - }, - "peerDependencies": { - "bare-buffer": "*", - "bare-events": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - }, - "bare-events": { - "optional": true - } - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/bcrypt": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", - "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.11", - "node-addon-api": "^5.0.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/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/body-parser/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/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buildcheck": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", - "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cacache/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", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/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", - "optional": true - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001698", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001698.tgz", - "integrity": "sha512-xJ3km2oiG/MbNU8G6zIq6XRZ6HtAOVXsbOrP/blGazi52kc5Yy7b6sDA5O+FbROzRrV7BSTllLHuNvmawYUJjw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-bidi": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-1.2.0.tgz", - "integrity": "sha512-XtdJ1GSN6S3l7tO7F77GhNsw0K367p0IsLYf2yZawCVAKKC3lUvDhPdMVrB2FNhmhfW43QGYbEX3Wg6q0maGwQ==", - "license": "Apache-2.0", - "dependencies": { - "mitt": "^3.0.1", - "zod": "^3.24.1" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "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==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "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" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "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==", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "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" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/cookiejar": { - "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, - "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==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "license": "MIT", - "dependencies": { - "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/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cpu-features": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", - "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "buildcheck": "~0.0.6", - "nan": "^2.19.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-require": { - "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, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cytoscape": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.31.0.tgz", - "integrity": "sha512-zDGn1K/tfZwEnoGOcHc0H4XazqAAXAuDpcYw9mUnUjATjqljyCNGJv8uEvbvxGaGHaVshxMecyl6oc6uKzRfbw==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-extend": { - "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", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dependency-cruiser": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/dependency-cruiser/-/dependency-cruiser-16.9.0.tgz", - "integrity": "sha512-Gc/xHNOBq1nk5i7FPCuexCD0m2OXB/WEfiSHfNYQaQaHZiZltnl5Ixp/ZG38Jvi8aEhKBQTHV4Aw6gmR7rWlOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "acorn-jsx-walk": "^2.0.0", - "acorn-loose": "^8.4.0", - "acorn-walk": "^8.3.4", - "ajv": "^8.17.1", - "commander": "^13.0.0", - "enhanced-resolve": "^5.18.0", - "ignore": "^7.0.0", - "interpret": "^3.1.1", - "is-installed-globally": "^1.0.0", - "json5": "^2.2.3", - "memoize": "^10.0.0", - "picocolors": "^1.1.1", - "picomatch": "^4.0.2", - "prompts": "^2.4.2", - "rechoir": "^0.8.0", - "safe-regex": "^2.1.1", - "semver": "^7.6.3", - "teamcity-service-messages": "^0.1.14", - "tsconfig-paths-webpack-plugin": "^4.2.0", - "watskeburt": "^4.2.2" - }, - "bin": { - "depcruise": "bin/dependency-cruise.mjs", - "depcruise-baseline": "bin/depcruise-baseline.mjs", - "depcruise-fmt": "bin/depcruise-fmt.mjs", - "depcruise-wrap-stream-in-html": "bin/wrap-stream-in-html.mjs", - "dependency-cruise": "bin/dependency-cruise.mjs", - "dependency-cruiser": "bin/dependency-cruise.mjs" - }, - "engines": { - "node": "^18.17||>=20" - } - }, - "node_modules/dependency-cruiser/node_modules/ignore": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", - "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/devtools-protocol": { - "version": "0.0.1402036", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1402036.tgz", - "integrity": "sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg==", - "license": "BSD-3-Clause" - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "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" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/docker-compose": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.1.0.tgz", - "integrity": "sha512-VrkQJNafPQ5d6bGULW0P6KqcxSkv3ZU5Wn2wQA19oB71o7+55vQ9ogFe2MMeNbK+jc9rrKVy280DnHO5JLMWOQ==", - "license": "MIT", - "dependencies": { - "yaml": "^2.2.2" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/docker-modem": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.6.tgz", - "integrity": "sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.1", - "readable-stream": "^3.5.0", - "split-ca": "^1.0.1", - "ssh2": "^1.15.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/dockerode": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.4.tgz", - "integrity": "sha512-6GYP/EdzEY50HaOxTVTJ2p+mB5xDHTMJhS+UoGrVyS6VC+iQRh7kZ4FRpUYq6nziby7hPqWhOrFFUFTMUZJJ5w==", - "license": "Apache-2.0", - "dependencies": { - "@balena/dockerignore": "^1.0.2", - "@grpc/grpc-js": "^1.11.1", - "@grpc/proto-loader": "^0.7.13", - "docker-modem": "^5.0.6", - "protobufjs": "^7.3.2", - "tar-fs": "~2.0.1", - "uuid": "^10.0.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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==", - "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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.96", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz", - "integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/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/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", - "dependencies": { - "once": "^1.4.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==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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", - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT", - "optional": true - }, - "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==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.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" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/eslint": { - "version": "9.20.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz", - "integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.11.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.20.0", - "@eslint/plugin-kit": "^0.2.5", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/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": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/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==", - "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==", - "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/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, - "node_modules/express/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/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/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "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/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "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/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-stream-rotator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", - "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", - "license": "MIT", - "dependencies": { - "moment": "^2.29.1" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/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/finalhandler/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/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true, - "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/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.2.tgz", - "integrity": "sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==", - "dev": true, - "license": "MIT", - "dependencies": { - "dezalgo": "^1.0.4", - "hexoid": "^2.0.0", - "once": "^1.4.0" - }, - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "function-bind": "^1.1.2", - "get-proto": "^1.0.0", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/get-uri": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", - "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/global-directory": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "4.1.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals": { - "version": "15.14.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", - "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "devOptional": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hexoid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-2.0.0.tgz", - "integrity": "sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "license": "BSD-2-Clause", - "optional": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/https": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", - "integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==", - "license": "ISC" - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/i": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", - "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.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==", - "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": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true, - "license": "ISC" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "license": "ISC", - "optional": true - }, - "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.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "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==", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "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": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", - "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "global-directory": "^4.0.1", - "is-path-inside": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", - "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT" - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "bin": { - "license-checker": "bin/license-checker" - } - }, - "node_modules/license-checker/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/license-checker/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/license-checker/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/license-checker/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/license-checker/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/license-checker/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/license-checker/node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/license-checker/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/license-checker/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/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==", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/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": { - "@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" - } - }, - "node_modules/long": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", - "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==", - "license": "Apache-2.0" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/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/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "license": "ISC", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/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", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/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", - "optional": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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": ">= 0.6" - } - }, - "node_modules/memoize": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/memoize/-/memoize-10.0.0.tgz", - "integrity": "sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sindresorhus/memoize?sponsor=1" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/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/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/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/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT" - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "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/nan": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", - "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", - "license": "MIT", - "optional": true - }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT" - }, - "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": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/node-abi": { - "version": "3.74.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", - "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "license": "MIT", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.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, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nodemailer": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", - "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", - "license": "MIT-0", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/nodemon": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", - "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/nodemon/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/nodemon/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nodemon/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/nodemon/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "license": "ISC", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.1.0.tgz", - "integrity": "sha512-rPMBrZud26lI/LcjQeLw/K5Hf1apXMKgkpNNEzp0YQYmM877+T1ZNKPcB2hnTi7e6fBNz8xLtMMn/w46fVUqGw==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/promise-spawn", - "@npmcli/redact", - "@npmcli/run-script", - "@sigstore/tuf", - "abbrev", - "archy", - "cacache", - "chalk", - "ci-info", - "cli-columns", - "fastest-levenshtein", - "fs-minipass", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minimatch", - "minipass", - "minipass-pipeline", - "ms", - "node-gyp", - "nopt", - "normalize-package-data", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "semver", - "spdx-expression-parse", - "ssri", - "supports-color", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which" - ], - "license": "Artistic-2.0", - "workspaces": [ - "docs", - "smoke-tests", - "mock-globals", - "mock-registry", - "workspaces/*" - ], - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.0.0", - "@npmcli/config": "^10.0.1", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^4.0.2", - "@npmcli/package-json": "^6.1.1", - "@npmcli/promise-spawn": "^8.0.2", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^9.0.1", - "@sigstore/tuf": "^3.0.0", - "abbrev": "^3.0.0", - "archy": "~1.0.0", - "cacache": "^19.0.1", - "chalk": "^5.4.1", - "ci-info": "^4.1.0", - "cli-columns": "^4.0.0", - "fastest-levenshtein": "^1.0.16", - "fs-minipass": "^3.0.3", - "glob": "^10.4.5", - "graceful-fs": "^4.2.11", - "hosted-git-info": "^8.0.2", - "ini": "^5.0.0", - "init-package-json": "^8.0.0", - "is-cidr": "^5.1.0", - "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^10.0.0", - "libnpmdiff": "^8.0.0", - "libnpmexec": "^10.0.0", - "libnpmfund": "^7.0.0", - "libnpmorg": "^8.0.0", - "libnpmpack": "^9.0.0", - "libnpmpublish": "^11.0.0", - "libnpmsearch": "^9.0.0", - "libnpmteam": "^8.0.0", - "libnpmversion": "^8.0.0", - "make-fetch-happen": "^14.0.3", - "minimatch": "^9.0.5", - "minipass": "^7.1.1", - "minipass-pipeline": "^1.2.4", - "ms": "^2.1.2", - "node-gyp": "^11.0.0", - "nopt": "^8.0.0", - "normalize-package-data": "^7.0.0", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^7.1.1", - "npm-package-arg": "^12.0.1", - "npm-pick-manifest": "^10.0.0", - "npm-profile": "^11.0.1", - "npm-registry-fetch": "^18.0.2", - "npm-user-validate": "^3.0.0", - "p-map": "^7.0.3", - "pacote": "^21.0.0", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.0.0", - "semver": "^7.6.3", - "spdx-expression-parse": "^4.0.0", - "ssri": "^12.0.0", - "supports-color": "^9.4.0", - "tar": "^6.2.1", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^3.0.0", - "validate-npm-package-name": "^6.0.0", - "which": "^5.0.0" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true, - "license": "ISC" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/agent": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/metavuln-calculator": "^9.0.0", - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.1", - "@npmcli/query": "^4.0.0", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^9.0.1", - "bin-links": "^5.0.0", - "cacache": "^19.0.1", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^8.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^10.2.2", - "minimatch": "^9.0.4", - "nopt": "^8.0.0", - "npm-install-checks": "^7.1.0", - "npm-package-arg": "^12.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.1", - "pacote": "^21.0.0", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "proggy": "^3.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "ssri": "^12.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^4.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "10.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/package-json": "^6.0.1", - "ci-info": "^4.0.0", - "ini": "^5.0.0", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "6.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^8.0.0", - "ini": "^5.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^10.0.0", - "proc-log": "^5.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "4.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cacache": "^19.0.0", - "json-parse-even-better-errors": "^4.0.0", - "pacote": "^21.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "6.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^6.1.2" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/redact": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "9.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "node-gyp": "^11.0.0", - "proc-log": "^5.0.0", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/core": { - "version": "2.0.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.3.3", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/sign": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "make-fetch-happen": "^14.0.1", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2", - "tuf-js": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/verify": { - "version": "2.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/@tufjs/models": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/agent-base": { - "version": "7.1.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "6.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/bin-links": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^7.0.0", - "npm-normalize-package-bin": "^4.0.0", - "proc-log": "^5.0.0", - "read-cmd-shim": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "19.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/cacache/node_modules/chownr": { - "version": "3.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/cacache/node_modules/minizlib": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/cacache/node_modules/mkdirp": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/cacache/node_modules/tar": { - "version": "7.4.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/cacache/node_modules/yallist": { - "version": "5.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/chalk": { - "version": "5.4.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ci-info": { - "version": "4.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "4.1.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^5.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "4.4.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/diff": { - "version": "7.0.0", - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.1", - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.16", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/npm/node_modules/foreground-child": { - "version": "3.3.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "10.4.5", - "inBundle": 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/npm/node_modules/graceful-fs": { - "version": "4.2.11", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.1", - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/ini": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^6.1.0", - "npm-package-arg": "^12.0.0", - "promzard": "^2.0.0", - "read": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/ip-address": { - "version": "9.0.5", - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "5.1.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^4.1.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/jackspeak": { - "version": "3.4.3", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/npm/node_modules/jsbn": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff": { - "version": "6.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.5.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "10.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "binary-extensions": "^3.0.0", - "diff": "^7.0.0", - "minimatch": "^9.0.4", - "npm-package-arg": "^12.0.0", - "pacote": "^21.0.0", - "tar": "^6.2.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "10.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.0.0", - "@npmcli/run-script": "^9.0.1", - "ci-info": "^4.0.0", - "npm-package-arg": "^12.0.0", - "pacote": "^21.0.0", - "proc-log": "^5.0.0", - "read": "^4.0.0", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.0.0", - "@npmcli/run-script": "^9.0.1", - "npm-package-arg": "^12.0.0", - "pacote": "^21.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "11.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ci-info": "^4.0.0", - "normalize-package-data": "^7.0.0", - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1", - "proc-log": "^5.0.0", - "semver": "^7.3.7", - "sigstore": "^3.0.0", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.1", - "@npmcli/run-script": "^9.0.1", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "10.4.3", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "14.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/make-fetch-happen/node_modules/negotiator": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "9.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/minipass": { - "version": "7.1.2", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm/node_modules/minipass-fetch/node_modules/minizlib": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minizlib": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/mkdirp": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "11.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/chownr": { - "version": "3.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/minizlib": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/tar": { - "version": "7.4.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/yallist": { - "version": "5.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/nopt/node_modules/abbrev": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "7.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^8.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "7.1.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "12.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "10.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "10.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^12.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "11.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "18.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^3.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^14.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^12.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch/node_modules/minizlib": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "3.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/p-map": { - "version": "7.0.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/package-json-from-dist": { - "version": "1.0.1", - "inBundle": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/npm/node_modules/pacote": { - "version": "21.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^10.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/path-scurry": { - "version": "1.11.1", - "inBundle": 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/npm/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/proc-log": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/proggy": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-inflight": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/read": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/rimraf": { - "version": "5.0.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/npm/node_modules/semver": { - "version": "7.6.3", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "4.1.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/sigstore": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "@sigstore/sign": "^3.0.0", - "@sigstore/tuf": "^3.0.0", - "@sigstore/verify": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.8.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.2.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.5.0", - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.21", - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/sprintf-js": { - "version": "1.1.3", - "inBundle": true, - "license": "BSD-3-Clause" - }, - "node_modules/npm/node_modules/ssri": { - "version": "12.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "9.4.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "6.2.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/treeverse": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/tuf-js": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "3.0.1", - "debug": "^4.3.6", - "make-fetch-happen": "^14.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/unique-filename": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/unique-slug": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/which": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/which/node_modules/isexe": { - "version": "3.1.1", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "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/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "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/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": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "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": { - "fn.name": "1.x.x" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pac-proxy-agent": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz", - "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==", - "license": "MIT", - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "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": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "license": "ISC", - "optional": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", - "optional": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "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" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/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": ">= 0.10" - } - }, - "node_modules/proxy-agent": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", - "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.6", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.1.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/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": ">=12" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/puppeteer": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.2.0.tgz", - "integrity": "sha512-z8vv7zPEgrilIbOo3WNvM+2mXMnyM9f4z6zdrB88Fzeuo43Oupmjrzk3EpuvuCtyK0A7Lsllfx7Z+4BvEEGJcQ==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "2.7.1", - "chromium-bidi": "1.2.0", - "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1402036", - "puppeteer-core": "24.2.0", - "typed-query-selector": "^2.12.0" - }, - "bin": { - "puppeteer": "lib/cjs/puppeteer/node/cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/puppeteer-core": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.2.0.tgz", - "integrity": "sha512-e4A4/xqWdd4kcE6QVHYhJ+Qlx/+XpgjP4d8OwBx0DJoY/nkIRhSgYmKQnv7+XSs1ofBstalt+XPGrkaz4FoXOQ==", - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "2.7.1", - "chromium-bidi": "1.2.0", - "debug": "^4.4.0", - "devtools-protocol": "0.0.1402036", - "typed-query-selector": "^2.12.0", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/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)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/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" - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-installed/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/readdirp": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", - "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", - "dev": true, - "license": "MIT", - "bin": { - "regexp-tree": "bin/regexp-tree" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "regexp-tree": "~0.1.1" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/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/send/node_modules/debug/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/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "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/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "*" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "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==", - "devOptional": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true, - "license": "(MIT AND CC-BY-3.0)" - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/split-ca": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", - "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", - "license": "ISC" - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" - }, - "node_modules/sqlite3": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", - "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/sqlite3/node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" - }, - "node_modules/ssh2": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.16.0.tgz", - "integrity": "sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==", - "hasInstallScript": true, - "dependencies": { - "asn1": "^0.2.6", - "bcrypt-pbkdf": "^1.0.2" - }, - "engines": { - "node": ">=10.16.0" - }, - "optionalDependencies": { - "cpu-features": "~0.0.10", - "nan": "^2.20.0" - } - }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/streamx": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", - "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/string_decoder": { - "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.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", - "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^3.5.1", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/supertest": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", - "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "methods": "^1.1.2", - "superagent": "^9.0.1" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swagger-ui-dist": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.3.tgz", - "integrity": "sha512-G33HFW0iFNStfY2x6QXO2JYVMrFruc8AZRX0U/L71aA7WeWfX2E5Nm8E/tsipSZJeIZZbSjUDeynLK/wcuNWIw==", - "license": "Apache-2.0", - "dependencies": { - "@scarf/scarf": "=1.4.0" - } - }, - "node_modules/swagger-ui-express": { - "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" - }, - "engines": { - "node": ">= v0.10.32" - }, - "peerDependencies": { - "express": ">=4.0.0 || >=5.0.0-beta" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-fs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", - "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.0.0" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/teamcity-service-messages": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/teamcity-service-messages/-/teamcity-service-messages-0.1.14.tgz", - "integrity": "sha512-29aQwaHqm8RMX74u2o/h1KbMLP89FjNiMxD9wbF2BbWOnbM+q+d1sCEC+MqCc4QW3NJykn77OMpTFw/xTHIc0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT" - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "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" - } - }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "license": "MIT", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/ts-jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.6.3", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "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", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "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", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tsconfig-paths-webpack-plugin": { - "version": "4.2.0", - "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", - "tapable": "^2.2.1", - "tsconfig-paths": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", - "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.23.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "license": "Unlicense" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-query-selector": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", - "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", - "license": "MIT" - }, - "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "devOptional": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.23.0.tgz", - "integrity": "sha512-/LBRo3HrXr5LxmrdYSOCvoAMm7p2jNizNfbIpCgvG4HMsnoprRUOce/+8VJ9BDYWW68rqIENE/haVLWPeFZBVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.23.0", - "@typescript-eslint/parser": "8.23.0", - "@typescript-eslint/utils": "8.23.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 <5.8.0" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true, - "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" - } - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "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" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/watskeburt": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/watskeburt/-/watskeburt-4.2.2.tgz", - "integrity": "sha512-AOCg1UYxWpiHW1tUwqpJau8vzarZYTtzl2uu99UptBmbzx6kOzCGMfRLF6KIRX4PYekmryn89MzxlRNkL66YyA==", - "dev": true, - "license": "MIT", - "bin": { - "watskeburt": "dist/run-cli.js" - }, - "engines": { - "node": "^18||>=20" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.7.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.9.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-daily-rotate-file": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz", - "integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==", - "license": "MIT", - "dependencies": { - "file-stream-rotator": "^0.6.1", - "object-hash": "^3.0.0", - "triple-beam": "^1.4.1", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "winston": "^3" - } - }, - "node_modules/winston-transport": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", - "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", - "license": "MIT", - "dependencies": { - "logform": "^2.7.0", - "readable-stream": "^3.6.2", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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==", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "glob": "^7.0.5" - }, - "bin": { - "json2yaml": "bin/json2yaml", - "yaml2json": "bin/yaml2json" - } - }, - "node_modules/yamljs/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/yamljs/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/package.json b/package.json index c48ee738..06509479 100644 --- a/package.json +++ b/package.json @@ -1,123 +1,45 @@ { "name": "dockstatapi", - "repository": "git@github.com:Its4Nik/dockstatapi.git", - "version": "2.0.1", - "description": "API for docker hosts using dockerode", - "main": "src/server.ts", + "author": { + "email": "info@itsnik.de", + "name": "ItsNik", + "url": "https://github.com/Its4Nik" + }, + "license": "CC BY-NC 4.0", + "contributors": [], + "description": "DockStatAPI is an API backend featuring plugins and more for DockStat", + "version": "2.1.0", "scripts": { - "test": "NODE_ENV=testing jest -w 1 --forceExit", - "test:silent": "NODE_ENV=testing jest -w 1 --forceExit --silent", - "local-env-file": "bash ./src/misc/createEnvDev.sh", - "start": "npm run local-env-file && NODE_ENV=production tsx src/server.ts", - "start:build": "npm run local-env-file -d && npm run build && NODE_ENV=production node dist/src/src/server.js", - "dev": "npm run local-env-file && NODE_ENV=development nodemon", - "dev:socket": "docker compose -f docker/docker-compose.dev.yaml up -d && npm run local-env-file && NODE_ENV=development nodemon ; docker compose -f docker/docker-compose.dev.yaml down", - "dev:trace": "npm run local-env-file && NODE_ENV=development nodemon --trace-uncaught --trace-warnings", - "dep": "bash ./src/misc/dependencyGraphs/createDependencyGraph.sh", - "dep:remove": "bash ./src/misc/removeUnusedDeps.sh && npm run dep", - "build": "tsc", - "build:mini": "tsc && bash ./src/misc/minifyDist.sh --build-only", - "build:docker": "docker build . -t \"dockstatapi:local\" -f ./docker/Dockerfile-dev", - "build:docker:prod": "docker build . -t \"dockstatapi:local\" -f ./docker/Dockerfile-base", - "mini": "bash ./src/misc/minifyDist.sh", - "docker": "docker compose -f docker/docker-compose.yaml up -d && bash ./src/misc/.tmux.sh; docker compose -f docker/docker-compose.yaml down", - "docker:build": "npm run build:docker && npm run docker", - "docker:build:prod": "npm run build:docker:prod && npm run docker", - "prettier": "prettier -c ./__tests__/*.spec.ts --parser typescript --write && prettier -c ./src/**/*.ts --parser typescript --write && prettier -c ./.github/workflows/*.yaml --parser yaml --write && prettier -c ./**/*.md --parser markdown --write && prettier -c ./**/*.json --parser json --write", - "lint": "eslint", - "lint:fix": "eslint --fix", - "license": "bash ./src/misc/credits.sh", - "finish": "npm run local-env-file && npm run license && npm run prettier && npm run lint" + "start": "cross-env NODE_ENV=production LOG_LEVEL=info bun run src/index.ts", + "start:linux": "NODE_ENV=production LOG_LEVEL=info bun run src/index.ts", + "dev": "docker compose -f docker/docker-compose.dev.yaml up -d && cross-env NODE_ENV=dev bun run --watch src/index.ts", + "dev:clean": "bun dev ; echo '\nExiting...' ; bun clean", + "build": "bun build --target bun src/index.ts --outdir ./dist", + "clean": "bun run clean:win || bun run clean:lin", + "clean:win": "node -e \"process.exit(process.platform === 'win32' ? 0 : 1)\" && cmd /c del /Q dockstatapi.db* && echo 'success'", + "clean:lin": "node -e \"process.exit(process.platform !== 'win32' ? 0 : 1)\" && rm -f dockstatapi.db* && echo 'success'" }, - "keywords": [], - "author": "Its4Nik", - "license": "BSD 3-Clause License", "dependencies": { - "bcrypt": "^5.1.1", - "chokidar": "^4.0.1", - "cors": "^2.8.5", - "cytoscape": "^3.30.4", - "docker-compose": "^1.1.0", - "dockerode": "^4.0.2", - "express": "^4.21.1", - "express-rate-limit": "^7.4.1", - "https": "^1.0.0", - "i": "^0.3.7", - "ipaddr.js": "^2.2.0", - "nodemailer": "^6.9.16", - "npm": "^11.0.0", - "puppeteer": "^24.0.0", - "sqlite3": "^5.1.7", - "swagger-ui-express": "^5.0.1", - "winston": "^3.15.0", - "winston-daily-rotate-file": "^5.0.0", - "yamljs": "^0.3.0" + "@elysiajs/static": "^1.2.0", + "@elysiajs/swagger": "^1.2.2", + "chalk": "^5.4.1", + "docker-compose": "^1.1.1", + "dockerode": "^4.0.4", + "elysia": "latest", + "split2": "^4.2.0", + "winston": "^3.17.0", + "winston-transport": "^4.9.0", + "yaml": "^2.7.0" }, "devDependencies": { - "@eslint/js": "^9.17.0", - "@types/bcrypt": "^5.0.2", - "@types/cors": "^2.8.17", - "@types/cytoscape": "^3.21.8", - "@types/dockerode": "^3.3.31", - "@types/express": "^5.0.0", - "@types/express-handlebars": "^5.3.1", - "@types/jest": "^29.5.14", - "@types/node": "^22.9.0", - "@types/node-fetch": "^2.6.12", - "@types/nodemailer": "^6.4.17", - "@types/supertest": "^6.0.2", - "@types/supports-color": "^8.1.3", - "@types/swagger-jsdoc": "^6.0.4", - "@types/swagger-ui-express": "^4.1.7", - "@types/ws": "^8.5.14", - "@types/yamljs": "^0.2.34", - "@typescript-eslint/eslint-plugin": "^8.18.2", - "@typescript-eslint/parser": "^8.18.2", - "dependency-cruiser": "^16.5.0", - "eslint": "^9.17.0", - "globals": "^15.14.0", - "jest": "^29.7.0", - "license-checker": "^25.0.1", - "nodemon": "^3.1.7", - "prettier": "^3.4.2", - "supertest": "^7.0.0", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2", - "tsx": "^4.19.2", - "typescript-eslint": "^8.18.2", - "uglify-js": "^3.19.3" - }, - "engines": { - "npm": ">=10.8.2" + "@types/dockerode": "^3.3.34", + "@types/split2": "^4.2.3", + "bun-types": "latest", + "cross-env": "^7.0.3", + "wrap-ansi": "^9.0.0" }, - "jest": { - "preset": "ts-jest", - "testMatch": [ - "**/__tests__/**/*.(test|spec).ts" - ], - "testEnvironment": "node", - "transform": { - "^.+\\.(ts|tsx)$": "ts-jest" - }, - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "coveragePathIgnorePatterns": [ - "/node_modules/" - ], - "moduleNameMapper": { - "^@/(.*)$": "src/$1" - }, - "transformIgnorePatterns": [ - "/node_modules/" - ], - "testPathIgnorePatterns": [ - "util" - ] - } -} + "module": "src/index.js", + "trustedDependencies": [ + "protobufjs" + ] +} \ No newline at end of file diff --git a/public/404.html b/public/404.html new file mode 100644 index 00000000..39b107d4 --- /dev/null +++ b/public/404.html @@ -0,0 +1,99 @@ + + + + + + + 404 - Page Not Found + + + + +
+ +
404
+
+ Oops! The page you're looking for doesn't exist. +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/.github/DockStat.png b/public/DockStat.png similarity index 100% rename from .github/DockStat.png rename to public/DockStat.png diff --git a/src/config/db.ts b/src/config/db.ts deleted file mode 100644 index 5ed4d6a0..00000000 --- a/src/config/db.ts +++ /dev/null @@ -1,23 +0,0 @@ -import sqlite3 from "sqlite3"; -import logger from "../utils/logger"; - -const dbPath: string = "./src/data/database.db"; - -const db: sqlite3.Database = new sqlite3.Database(dbPath, (error: unknown) => { - if (error as Error) { - logger.error("Error opening database:", (error as Error).message); - } else { - db.run( - `CREATE TABLE IF NOT EXISTS data ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - info TEXT NOT NULL, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP - )`, - () => { - logger.info("Database created / checked successfully, table is ready."); - }, - ); - } -}); - -export default db; diff --git a/src/config/hostsystem.ts b/src/config/hostsystem.ts deleted file mode 100644 index 87928a8e..00000000 --- a/src/config/hostsystem.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - RUNNING_IN_DOCKER, - VERSION, - HA_MASTER, - HA_UNSAFE, - TRUSTED_PROXIES, - LOG_LEVEL, -} from "./variables"; -import fs from "fs"; -import logger from "../utils/logger"; -import os from "os"; -import { atomicWrite } from "../utils/atomicWrite"; - -const userConf = "./src/data/user.conf"; -const inDocker: boolean = RUNNING_IN_DOCKER == "true"; -const version: string = VERSION || "unknown"; -const masterNode: string = HA_MASTER === "true" ? "✓" : "✗"; -const unsafeSync: string = HA_UNSAFE === "true" ? "✓" : "✗"; - -let trustedProxies: string = ""; - -if (TRUSTED_PROXIES) { - trustedProxies = TRUSTED_PROXIES; -} else { - trustedProxies = "✗"; -} - -function writeUserConf(port: number) { - let previousConfig = null; - let shouldRewriteConfig = false; - - const installationDetails = { - installedAt: new Date().toISOString(), - backendVersion: version, - inDocker: inDocker, - installedBy: os.userInfo().username, - platform: os.platform(), - arch: os.arch(), - }; - - if (fs.existsSync(userConf)) { - try { - previousConfig = JSON.parse(fs.readFileSync(userConf, "utf-8")); - if (previousConfig.backendVersion !== version) { - shouldRewriteConfig = true; - logger.debug( - "Version change detected. Rewriting configuration file...", - ); - } else { - logger.debug("No version change detected. Skipping re-initialization."); - } - } catch (error) { - logger.error( - "Error reading the configuration file. Rewriting it...", - error, - ); - shouldRewriteConfig = true; - } - } else { - logger.debug("Configuration file not found. Creating a new one..."); - shouldRewriteConfig = true; - } - - if (shouldRewriteConfig) { - atomicWrite(userConf, JSON.stringify(installationDetails, null, 2)); - logger.debug("Configuration file created/updated:", userConf); - } - - const startDetails = { - startedAt: new Date().toISOString(), - backendVersion: version, - }; - - logger.info("-----------------------------------------"); - logger.info(`Starting at : ${startDetails.startedAt}`); - logger.info(`Running env : ${process.env.NODE_ENV}`); - logger.info(`Version : ${startDetails.backendVersion}`); - logger.info(`Docker : ${installationDetails.inDocker}`); - logger.info(`Running as : ${installationDetails.installedBy}`); - logger.info(`Platform : ${installationDetails.platform}`); - logger.info(`Arch : ${installationDetails.arch}`); - logger.info(`Master node : ${masterNode}`); - logger.info(`Unsafe sync : ${unsafeSync}`); - logger.info(`Proxies : ${trustedProxies}`); - logger.info(`Log Level : ${LOG_LEVEL}`); - logger.info(`Server : http://localhost:${port}`); - if (process.env.NODE_ENV !== "production") { - logger.info(`Swagger-UI : http://localhost:${port}/api-docs`); - } - logger.info("-----------------------------------------"); -} - -export default writeUserConf; diff --git a/src/config/initFiles.ts b/src/config/initFiles.ts deleted file mode 100644 index 7524907c..00000000 --- a/src/config/initFiles.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { existsSync } from "fs"; -import logger from "../utils/logger"; -import { atomicWrite } from "../utils/atomicWrite"; - -const files = [ - { path: "./src/data/highAvailability.json", content: "{}" }, - { - path: "./src/data/password.json", - content: JSON.stringify( - { - hash: "", - salt: "", - }, - null, - 2, - ), - }, - { path: "./src/data/states.json", content: "{}" }, - { - path: "./src/data/template.json", - content: JSON.stringify( - { text: "{{name}} is {{state}} on {{hostName}}" }, - null, - 2, - ), - }, - { path: "./src/data/frontendConfiguration.json", content: "[]" }, - { path: "./src/data/usePassword.txt", content: "false" }, -]; - -function initFiles(): void { - files.forEach(({ path: filePath, content }) => { - if (!existsSync(filePath)) { - atomicWrite(filePath, content); - logger.info(`Created: ${filePath}`); - } else { - logger.debug(`Skipped (already exists): ${filePath}`); - } - }); -} - -export default initFiles; diff --git a/src/config/stacks.ts b/src/config/stacks.ts deleted file mode 100644 index def75dcb..00000000 --- a/src/config/stacks.ts +++ /dev/null @@ -1,260 +0,0 @@ -import logger from "../utils/logger"; -import fs from "fs"; -import path from "path"; -import YAML from "yamljs"; -import { DockerComposeFile } from "../typings/dockerCompose"; -import { dockerStackProperty, dockerStackEnv } from "../typings/dockerStackEnv"; -import { stackConfig } from "../typings/stackConfig"; -import { validate } from "../handlers/stack"; -import { atomicWrite } from "../utils/atomicWrite"; -import { AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT } from "./variables"; - -const nameRegex = /^[A-Za-z0-9_-]+$/; -const stackRootFolder = "./stacks"; -const configFilePath = `${stackRootFolder}/.config.json`; - -async function getStackCompose(name: string) { - try { - await validate(name); - const stackCompose = `${stackRootFolder}/${name}/docker-compose.yaml`; - - return YAML.parse(fs.readFileSync(stackCompose, "utf-8")); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - throw new Error(errorMsg); - } -} - -async function getStackConfig(): Promise { - try { - return fs.readFileSync(configFilePath, "utf-8"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - throw new Error(errorMsg); - } -} - -async function createStack( - name: string, - content: DockerComposeFile, - override: boolean, -) { - try { - if (!name) { - const errorMsg = "Name required"; - logger.error(errorMsg); - throw new Error(errorMsg); - } - - if (!nameRegex.test(name)) { - const errorMsg = "Name does not match [A-Za-z0-9_-]"; - logger.error(errorMsg); - throw new Error(errorMsg); - } - - if (!content) { - const errorMsg = "Data for this stack is required"; - logger.error(errorMsg); - throw new Error(errorMsg); - } - - const stackFolderPath = `${stackRootFolder}/${name}`; - - if (!fs.existsSync(stackFolderPath)) { - fs.mkdirSync(stackFolderPath, { recursive: true }); - logger.debug(`Created stack folder at ${stackFolderPath}`); - } - - updateConfigFile(name); - - let yamlContent = ""; - let environmentFileData: dockerStackEnv = { environment: [] }; - if (AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT == "true" && override == false) { - logger.debug("AEFM is activated"); - const { cleanCompose, envSchema } = extractAndRemoveEnv(content); - yamlContent = YAML.stringify(cleanCompose, 10, 2); - environmentFileData = envSchema; - - await writeEnvFile(name, environmentFileData); - } else { - yamlContent = YAML.stringify(content, 10, 2); - } - - const filePath = `${stackFolderPath}/docker-compose.yaml`; - atomicWrite(filePath, yamlContent); - logger.debug(`Stack content written to ${filePath}`); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - throw new Error(errorMsg); - } -} - -function updateConfigFile(stackName: string) { - try { - let config: stackConfig = { stacks: [] }; - if (fs.existsSync(configFilePath)) { - const configData = fs.readFileSync(configFilePath, "utf-8"); - config = JSON.parse(configData); - } - - const stacks = config.stacks || []; - - if (!stacks.includes(stackName)) { - stacks.push(stackName); - } - - const updatedConfig = { stacks }; - atomicWrite(configFilePath, JSON.stringify(updatedConfig, null, 2)); - logger.debug(`Updated .config.json with stack name: ${stackName}`); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(`Error updating .config.json: ${errorMsg}`); - throw new Error(errorMsg); - } -} - -async function writeEnvFile( - name: string, - data: dockerStackEnv, -): Promise { - try { - await validate(name); - - if (!nameRegex.test(name)) { - const sanitizedStackName = name.replace(/\n|\r/g, ""); - const errorMsg = `Invalid stack name: ${sanitizedStackName}`; - logger.error(errorMsg); - return false; - } - - const dockerEnvPath = path.resolve(stackRootFolder, name, "docker.env"); - const dockerEnvPathBak = path.resolve( - stackRootFolder, - name, - ".docker.env.bak", - ); - - if ( - !dockerEnvPath.startsWith(path.resolve(stackRootFolder)) || - !dockerEnvPathBak.startsWith(path.resolve(stackRootFolder)) - ) { - const sanitizedStackName = name.replace(/\n|\r/g, ""); - const errorMsg = `Path traversal attempt detected: ${sanitizedStackName}`; - logger.error(errorMsg); - return false; - } - - const variableNames = data.environment.map(({ name }) => name); - const duplicateVars = variableNames.filter( - (item, index) => variableNames.indexOf(item) !== index, - ); - - if (duplicateVars.length > 0) { - const duplicatesList = duplicateVars.join(", "); - const sanitizedDuplicatesList = duplicatesList.replace(/\n|\r/g, ""); - const errorMsg = `Duplicate environment variables detected: ${sanitizedDuplicatesList}`; - logger.error(errorMsg); - return false; - } - - const envFileContent = data.environment - .map(({ name, value }) => `${name}="${value}"`) - .join("\n"); - - if (fs.existsSync(dockerEnvPath)) { - logger.debug("Creating a local backup"); - const previousData = fs.readFileSync(dockerEnvPath); - atomicWrite(dockerEnvPathBak, previousData); - } - - atomicWrite(dockerEnvPath, envFileContent); - return true; - } catch (error: unknown) { - const errorMsg = ( - error instanceof Error ? error.message : String(error) - ).replace(/\n|\r/g, ""); - logger.error(errorMsg); - throw new Error(errorMsg); - } -} - -async function getEnvFile(name: string) { - await validate(name); - const dockerEnvPath = path.resolve(stackRootFolder, name, "docker.env"); - if (!dockerEnvPath.startsWith(path.resolve(stackRootFolder))) { - throw new Error("Invalid path"); - } - - if (fs.existsSync(dockerEnvPath)) { - const data = fs.readFileSync(dockerEnvPath, "utf-8"); - - const environment: dockerStackProperty[] = data - .split("\n") - .filter((line) => line.trim() !== "" && line.includes("=")) - .map((line) => { - const [name, ...valueParts] = line.split("="); - const value = valueParts.join("=").replace(/^"|"$/g, ""); - return { name: name.trim(), value: value.trim() }; - }); - - return { environment }; - } else { - return null; - } -} - -function extractAndRemoveEnv(data: DockerComposeFile): { - cleanCompose: DockerComposeFile; - envSchema: dockerStackEnv; -} { - const environment: dockerStackProperty[] = []; - const envCount: Record = {}; - - for (const [, service] of Object.entries(data.services)) { - if (service.environment) { - for (const key of Object.keys(service.environment)) { - envCount[key] = (envCount[key] || 0) + 1; - } - } - } - - for (const [, service] of Object.entries(data.services)) { - if (service.environment) { - const remainingEnvironment: Record = {}; - - for (const [key, value] of Object.entries(service.environment)) { - if (envCount[key] === 1) { - environment.push({ name: key, value }); - } else { - remainingEnvironment[key] = value; - } - } - - service.environment = remainingEnvironment; - - if (Object.keys(service.environment).length === 0) { - delete service.environment; - } - } - - if (!service.env_file) { - service.env_file = ["./docker.env"]; - } - } - - return { - cleanCompose: data, - envSchema: { environment }, - }; -} - -export { - createStack, - getStackConfig, - getStackCompose, - writeEnvFile, - getEnvFile, -}; diff --git a/src/config/swagger.yaml b/src/config/swagger.yaml deleted file mode 100644 index 2230f73b..00000000 --- a/src/config/swagger.yaml +++ /dev/null @@ -1,2084 +0,0 @@ -openapi: "3.0.0" - -security: - - passwordAuth: [] - -info: - title: "DockStatAPI" - version: "2.0.1" - externalDocs: - description: DockStat(API) Wiki - url: https://outline.itsnik.de/s/dockstat - license: - name: BSD-3-Clause - url: https://github.com/Its4Nik/dockstatapi/tree/main?tab=BSD-3-Clause-1-ov-file#readme - contact: - email: info@itsnik.de - description: |- - ![DockStat](https://github.com/Its4Nik/dockstatapi/blob/dev/.github/DockStat-dark.png?raw=true) - - # Pipelines - - [![Docker Image CI](https://img.shields.io/github/actions/workflow/status/Its4Nik/dockstatapi/build-image.yml?branch=main&label=Docker%20Image%20CI&style=for-the-badge&logo=docker)](https://github.com/Its4Nik/dockstatapi/actions/workflows/build-image.yml) - [![Validation](https://img.shields.io/github/actions/workflow/status/Its4Nik/dockstatapi/validation.yml?branch=dev&label=Validation&style=for-the-badge&logo=checkmarx)](https://github.com/Its4Nik/dockstatapi/actions/workflows/validation.yml) - - # Feature List: - - - Swagger API Documentation - - Database (Keeps data for 24 hours max) - - Advanced authentication using hashes and salt - - `http` API to configure the backend - - Multi-arch docker builds (using buildx github action) - - Advanced security through middlewares: rate-limiting and authentication - - Multi Arch Docker builds through docker buildx - - High Availability using single master and unlimited worker nodes! - - # 🔗 DockStatAPI v2 Documentation - - _⚠️ = Deprecation warning_ - - - [Introduction](https://outline.itsnik.de/s/dockstat) - - - [DockstatAPI v2](https://outline.itsnik.de/s/dockstat/doc/dockstatapi-v2-XRMDKRqMIg) - - - [API reference](https://outline.itsnik.de/s/dockstat/doc/api-reference-1PTxqx1MQ6) - - [How dependency graphs are made](https://outline.itsnik.de/s/dockstat/doc/how-the-dependecy-graphs-are-made-svuZbEHH9g) - - - [DockStat v1](https://outline.itsnik.de/s/dockstat/doc/dockstat-v1-zVaFS4zROI) - - - [⚠️ Customisation](https://outline.itsnik.de/s/dockstat/doc/customization-PiBz4OpQIZ) - - [⚠️ Themes](https://outline.itsnik.de/s/dockstat/doc/themes-BFhN6ZBbYx) - - [⚠️ Installation](https://outline.itsnik.de/s/dockstat/doc/installation-DaO99bB86q) - - - [⚠️ DockStatAPI v1](https://outline.itsnik.de/s/dockstat/doc/dockstatapi-v1-jLcVCfPNmS) - - [⚠️ Integrations](https://outline.itsnik.de/s/dockstat/doc/integrations-Agq1oL6HxF) - - [⚠️ Backend API reference](https://outline.itsnik.de/s/dockstat/doc/backend-api-reference-YzcBbDvY33) - -tags: - - name: Authentication - description: Routes to setup / configure authentication - - - name: Configuration - description: Configuring the backend - - - name: Database queries - description: Queries made against the SQLite database - - - name: "Frontend Configuration" - description: Backend routes to configure the integrated "frontend service" - - - name: Miscellaneous - description: Some "random" routes which still can be useful - - - name: High availability - description: High availability routes, mainly used by HA sync - - - name: Notification Service - description: Routes to configure the notification service - - - name: Stacks - description: Management of the Stack module - -servers: - - url: http://localhost:9876 - description: "Your DockStatAPI instance" - -paths: - # ------------------------------ - # Authentication setup: - /auth/enable: - post: - tags: - - "Authentication" - summary: Enable authentication for every route - operationId: enableAuth - parameters: - - name: password - in: query - required: true - explode: true - schema: - type: string - default: super-secret - responses: - "200": - description: Success - Successfully enabled authentication - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Authentication enabled successfully" - - "403": - description: Error - Password is required / Authentication is already enabled - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /auth/disable: - post: - tags: - - "Authentication" - summary: Disable authentication for every route - operationId: disableAuth - parameters: - - name: password - in: query - required: true - explode: true - schema: - type: string - default: super-secret - responses: - "200": - description: Succes - Succesfully disabled authentication - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Authentication disabled successfully" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - # ------------------------------ - # Database queries: - /data/latest: - get: - tags: - - "Database queries" - summary: Fetched the last added entry from the Database and provides it via a JSON output - operationId: getLatestData - responses: - "200": - description: Succes - Successfully fetched the database - content: - application/json: - schema: - $ref: "#/components/schemas/ServerContainers" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "404": - description: Error - No entries found inside database - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /data/all: - get: - tags: - - "Database queries" - summary: Provides all database entries with an index starting from 0 - operationId: getAllData - responses: - "200": - description: Succes - Successfully fetched the database - content: - application/json: - schema: - $ref: "#/components/schemas/IndexedServerContainers" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "404": - description: Error - No entries found inside database - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /data/clear: - delete: - tags: - - "Database queries" - summary: Deletes all database entries - operationId: dataClear - responses: - "200": - description: Succes - Successfully cleared the database - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Successfully cleared the database" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - # ------------------------------ - # Configuration: - /api/hosts: - get: - tags: - - "Configuration" - summary: Retrieves the configured name of all added Hosts - operationId: getHosts - responses: - "200": - description: Succes - Successfully fetched all configured hosts - content: - application/json: - schema: - type: array - example: '[ "Host-1", "Host-2" ]' - - "400": - description: Error - No hosts defined, please add a host via /conf/addHost - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/host/{hostName}/stats: - get: - tags: - - "Configuration" - summary: Shows general information about the target host, like dockeer engine version - operationId: getHostInfo - parameters: - - name: hostName - in: path - description: Hostname of the target host - required: true - schema: - type: string - responses: - "200": - description: Succes - Successfully fetched info about target host - content: - application/json: - schema: - $ref: "#/components/schemas/HostInfo" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "404": - description: Error - No Host found - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/system: - get: - tags: - - "Configuration" - summary: Fetched the installation details of this DockStatAPI instance - operationId: getSystem - responses: - "200": - description: Succes - Fetched system configuration - content: - application/json: - schema: - type: object - properties: - installedAt: - type: string - format: date-time - example: "2024-12-25T19:20:02.418Z" - backendVersion: - type: string - example: "2.0.1" - inDocker: - type: boolean - example: false - installedBy: - type: string - example: "user" - platform: - type: string - example: "linux" - arch: - type: string - example: "x64" - "400": - description: Error - Received empty configuration - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/config: - get: - tags: - - "Configuration" - summary: Retrieves information about the configured hosts - operationId: getConfig - responses: - "200": - description: Succes - Fetched system configuration - content: - application/json: - schema: - type: object - properties: - hosts: - type: array - items: - type: object - properties: - name: - type: string - example: "Host-1" - url: - type: string - example: "192.168.2.12" - port: - type: string - example: "2375" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/frontend-config: - get: - tags: - - "Configuration" - summary: Fetches the "Frontend Configuration" => Used in the DockStat frontend - operationId: getFrontendConfig - responses: - "200": - description: Succes - Fetched "Frontend Configuration" - content: - application/json: - schema: - $ref: "#/components/schemas/FrontendConfig" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/current-schedule: - get: - tags: - - "Configuration" - summary: Shows the current configured schedule (for fetching data) in seconds - operationId: getSchedule - responses: - "200": - description: Succes - Fetched schedule - content: - application/json: - schema: - type: object - properties: - interval: - type: integer - example: 600 - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/status: - get: - tags: - - "Miscellaneous" - summary: Pings all hosts to check reachability - operationId: getStatus - responses: - "200": - description: Succes - Gathered Status - content: - application/json: - schema: - $ref: "#/components/schemas/ApiStatus" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /api/containers: - get: - tags: - - "Miscellaneous" - summary: Fetched all container data directly from the host without reading from the database - operationId: getContainers - responses: - "200": - description: Succes - Fetched all container statistics - content: - application/json: - schema: - $ref: "#/components/schemas/ServerContainers" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - # ------------------------------ - # High availability: - /ha/config: - get: - tags: - - "High availability" - summary: Get the current high availability config - operationId: getHaConfig - responses: - "200": - description: Succes - Fetched high availability config - content: - application/json: - schema: - $ref: "#/components/schemas/HaConfig" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - - /ha/sync: - post: - tags: - - "High availability" - deprecated: true - summary: This route is not deprecated, but only used by the high availability feature - operationId: syncHa - responses: - "200": - description: Succes - Synchronized successfully - "400": - description: Error - `files` object is missing or invalid - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - - /ha/prepare-sync: - get: - tags: - - "High availability" - deprecated: true - summary: This route is not deprecated, but only used by the high availability feature - operationId: syncPrepare - responses: - "200": - description: Succes - Prepared all files for syncing - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - - # ------------------------------ - # Notification Service: - /notification-service/get-template: - get: - tags: - - "Notification Service" - summary: Fetches the current template for the notification service - operationId: getNsTemplate - responses: - "200": - description: Success - Fetched notification template - content: - application/json: - schema: - $ref: "#/components/schemas/Notification-Template" - "400": - description: Error - Error while reading file (see server logs) - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /notification-service/set-template: - post: - tags: - - "Notification Service" - - "Configuration" - summary: Update the current notification template - operationId: setNsTemplate - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/Notification-Template" - responses: - "200": - description: Success - Template updated successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Template updated successfully." - "400": - description: Error - Invalid input format. Expected JSON with a 'text' field - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Invalid input format. Expected JSON with a 'text' field" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /notification-service/test/{type}/{containerId}: - post: - tags: - - "Notification Service" - summary: Test a specific type of notification using real data - operationId: testNs - parameters: - - in: path - name: type - required: true - schema: - type: string - description: The desired notification to test - - - in: path - name: containerId - required: true - schema: - type: string - description: A real container ID is needed to test templating functionality - responses: - "200": - description: Success - Sent test notification - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Sent test notification" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - # ------------------------------ - # Configuration: - /conf/addHost: - put: - tags: - - "Configuration" - summary: Adds a new host to the configuration and starts querying it - operationId: addHost - parameters: - - name: name - in: query - required: true - description: A name for the new host - - name: url - in: query - required: true - description: The target IP or dns entry - - name: port - in: query - required: true - description: The targets port on which Docker-Socket-Proxy runs - responses: - "200": - description: Success - Host added successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Host added successfully" - "400": - description: Error - Name, Port, and URL are required - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Name, Port, and URL are required" - "401": - description: Host already exists - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Host already exists" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /conf/removeHost: - delete: - tags: - - "Configuration" - summary: Removes an host from the config - operationId: removeHost - parameters: - - name: hostName - in: query - required: true - description: "The name of the to-be-removed-Host" - responses: - "200": - description: Success - Host removed successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Host removed successfully" - "401": - description: Error - Host name is required - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Host name is required" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "404": - description: Error - Host not found - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Host not found" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /conf/scheduler: - tags: - - "Configuration" - summary: Adjust the scheduler timing - operationId: adjustSchedule - parameters: - - name: interval - in: query - required: true - description: "Adjust the schedule timing (in seconds)" - responses: - "200": - description: Success - Timing updated - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Updated interval" - "401": - description: Error - Interval must be between 5 minutes and 6 hours - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Interval must be between 5 minutes and 6 hours." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - # ------------------------------ - # Frontend routes: - /frontend/show/{containerName}: - post: - tags: - - "Frontend Configuration" - operationId: frShowCon - summary: Set `hide` to false for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to unhide - responses: - "200": - description: Success - now showing the container - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Container unhidden successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/hide/{containerName}: - delete: - tags: - - "Frontend Configuration" - operationId: frHideCon - summary: Set `hide` to true for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to unhide - responses: - "200": - description: Success - now hiding the container - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Hid container succesfully" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/tag/{containerName}/{tag}: - post: - tags: - - "Frontend Configuration" - operationId: frTagCon - summary: Add a tag to the tag array for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to add a tag to - - name: tag - in: path - schema: - type: string - required: true - description: The name of the tag to add - responses: - "200": - description: Success - Tag added successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Tag added successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/remove-tag/{containerName}/{tag}: - delete: - tags: - - "Frontend Configuration" - operationId: frRmTagCon - summary: Remove the specified tag from the tag array for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to remove a tag from - - name: tag - in: path - schema: - type: string - required: true - description: The name of the tag to remove - responses: - "200": - description: Success - Tag removed successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Tag removed successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/pin/{containerName}: - post: - tags: - - "Frontend Configuration" - operationId: frPinCon - summary: Set `pinned` to true for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to pin - responses: - "200": - description: Success - Container pinned successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Container pinned successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/unpin/{containerName}: - delete: - tags: - - "Frontend Configuration" - operationId: frRmPinCon - summary: Set `pinned` to false for the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to unpin - responses: - "200": - description: Success - Container unpinned successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Container unpinned successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/add-link/{containerName}/{link}: - post: - tags: - - "Frontend Configuration" - operationId: frAddLinkCon - summary: Add a link to the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to add a link to - - name: link - in: path - schema: - type: URI - required: true - allowReserved: false - description: The URI of the link (please use Uniform Resource Identifier format) - responses: - "200": - description: Success - Link added to container successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Link added successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/remove-link/{containerName}: - delete: - tags: - - "Frontend Configuration" - operationId: frRmLinkCon - summary: Remove a link to the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to remove a link from - responses: - "200": - description: Success - Link removed from container successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Link removed successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/add-icon/{containerName}/{icon}/{useCustomIcon}: - post: - tags: - - "Frontend Configuration" - operationId: frAddIcon - summary: Add an icon (path) to the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to add an icon to - - name: icon - in: path - schema: - type: string - required: true - description: The name of the icon file - - name: useCustomIcon - in: path - schema: - type: boolean - required: false - description: If the icon is a custom icon or not - responses: - "200": - description: Success - Icon added to container successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Icon added successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /frontend/remove-icon/{containerName}: - delete: - tags: - - "Frontend Configuration" - operationId: frRmIcon - summary: Remove an icon from the specified container - parameters: - - name: containerName - in: path - schema: - type: string - required: true - description: The name of the container to remove an icon from - responses: - "200": - description: Success - Icon removed from container successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Icon removed successfully." - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - # ------------------------------ - # Stack management - /stacks/create/{name}: - post: - tags: - - "Stacks" - operationId: createStack - summary: Creates a docker-compose file inside the stack name directory - requestBody: - required: true - content: - application/json: - schema: - type: string - description: Your docker-compose.yaml contents - parameters: - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack created - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Stack created" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /stacks/start/{name}: - post: - tags: - - "Stacks" - operationId: startStack - summary: Starts the defined stack - parameters: - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack started - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Stack created" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /stacks/stop/{name}: - post: - tags: - - "Stacks" - operationId: stopStack - summary: Stops the defined stack - parameters: - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack stopped - content: - application/json: - schema: - type: object - properties: - status: - type: string - example: "success" - message: - type: string - example: "Stack stopped" - - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /stacks/get/{name}: - get: - tags: - - "Stacks" - operationId: getStack - summary: Get the docker-compose.yaml (as JSON) from the defined stack - parameters: - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack fetched - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /stacks/set-env/{name}: - post: - tags: - - "Stacks" - operationId: setStackEnv - summary: Set the docker.env (as JSON) from the defined stack - requestBody: - required: true - content: - application/json: - schema: - type: string - description: Your docker.env contents - parameters: - - name: override - in: query - required: false - description: Whether to override (true) the automatic environment file management (boolean value) - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack environment set - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - - /stacks/get-env/{name}: - get: - tags: - - "Stacks" - operationId: getStackEnv - summary: Get the docker.env (as JSON) from the defined stack - parameters: - - name: name - in: path - schema: - type: string - required: true - description: The name of the stack - responses: - "200": - description: Success - Stack config fetched - "403": - description: Error - Password is required - content: - application/json: - schema: - $ref: "#/components/schemas/403" - "500": - description: Error - Critical Error, please see the server's logs - content: - application/json: - schema: - $ref: "#/components/schemas/500" - "503": - description: Error - The high-availability lock is currently active, please try again later - content: - application/json: - schema: - $ref: "#/components/schemas/503" - -# ------------------------------ -components: - securitySchemes: - passwordAuth: - type: apiKey - in: header - name: x-password - description: Password required for authentication - - schemas: - Notification-Template: - type: object - properties: - text: - type: string - example: "{{container}} on {{host}} is {{state}}" - - IndexedServerContainers: - type: object - properties: - "0": - type: object - properties: - Host-1: - type: array - items: - $ref: "#/components/schemas/Container" - additionalProperties: false - - ServerContainers: - type: object - properties: - Host-1: - type: array - items: - $ref: "#/components/schemas/Container" - additionalProperties: false - - Container: - type: object - properties: - name: - type: string - description: The name of the container. - example: "Container-1" - id: - type: string - description: The unique identifier of the container. - example: "a84ca83bb0e7f8c24fe472b9164d40a4bae518ece8369e6776f722b81dd65bcf" - hostName: - type: string - description: The hostname of the server. - example: "Host-1" - state: - type: string - description: The current state of the container. - example: "running" - cpu_usage: - type: number - description: The CPU usage of the container in arbitrary units. - example: 625185.1851851852 - mem_usage: - type: integer - description: Memory usage in bytes. - example: 359899136 - mem_limit: - type: integer - description: Memory limit in bytes. - example: 8127893504 - net_rx: - type: integer - description: Total network received in bytes. - example: 11004185462 - net_tx: - type: integer - description: Total network transmitted in bytes. - example: 9950013623 - current_net_rx: - type: integer - description: Current network received in bytes. - example: 11004185462 - current_net_tx: - type: integer - description: Current network transmitted in bytes. - example: 9950013623 - networkMode: - type: string - description: The network mode of the container. - example: "docker_default" - - HostInfo: - type: object - properties: - hostName: - type: string - example: "Host-1" - info: - type: object - properties: - ID: - type: string - format: uuid - example: "32b5fad9-9b12-48b0-9ce7-178f2886ad60" - Containers: - type: integer - example: 8 - ContainersRunning: - type: integer - example: 8 - ContainersPaused: - type: integer - example: 0 - ContainersStopped: - type: integer - example: 0 - Images: - type: integer - example: 7 - OperatingSystem: - type: string - example: "Ubuntu 24.04 LTS" - KernelVersion: - type: string - example: "6.8.0-38-generic" - Architecture: - type: string - example: "x86_64" - MemTotal: - type: integer - example: 8127893504 - NCPU: - type: integer - example: 4 - version: - type: object - properties: - Components: - type: object - properties: - Engine: - type: string - example: "27.1.1" - containerd: - type: string - example: "1.7.19" - runc: - type: string - example: "1.7.19" - docker-init: - type: string - example: "0.19.0" - - Frontend: - type: object - properties: - name: - type: string - description: The name of the container - hidden: - type: boolean - description: Whether the container is hidden - tags: - type: array - items: - type: string - description: List of tags associated with the container - link: - type: string - format: uri - description: A link associated with the container - icon: - type: string - description: Icon for the container - pinned: - type: boolean - description: Whether the container is pinned - required: - - name - - FrontendConfig: - type: array - items: - $ref: "#/components/schemas/Frontend" - - ApiStatus: - type: object - properties: - ApiReachable: - type: boolean - description: Whether the API is reachable - online: - type: object - description: Status of individual services keyed by their names - properties: - Host-1: - type: boolean - Host-2: - type: boolean - required: - - ApiReachable - - online - - HaConfig: - type: object - properties: - active: - type: boolean - description: Whether High availability is active or nots - master: - type: boolean - description: Whether this node is the master node - nodes: - type: array - items: - type: string - format: hostname - description: List of nodes in the cluster, specified by hostname or IP with port - required: - - active - - master - - nodes - - 401: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Invalid password" - - 403: - type: object - properties: - status: - type: string - example: "denied" - message: - type: string - example: "Password required" - - 500: - type: object - properties: - status: - type: string - example: "critical" - message: - type: string - example: "Please see the server logs for more info" - - 503: - type: object - properties: - status: - type: string - example: "error" - message: - type: string - example: "Service unavailable. The high-availability lock is currently active. Please try again later." diff --git a/src/config/swaggerConfig.ts b/src/config/swaggerConfig.ts deleted file mode 100644 index 39c074a6..00000000 --- a/src/config/swaggerConfig.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { SwaggerOptions } from "swagger-ui-express"; -import { css } from "./swaggerTheme"; - -export const options: SwaggerOptions = { - swaggerOptions: { - tryItOutEnabled: true, - }, - customCss: css, - explorer: false, -}; diff --git a/src/config/swaggerTheme.ts b/src/config/swaggerTheme.ts deleted file mode 100644 index d8a879c9..00000000 --- a/src/config/swaggerTheme.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const css = ` - -.swagger-ui .topbar { - display: none -} -`; diff --git a/src/config/variables.ts b/src/config/variables.ts deleted file mode 100644 index 37c67a23..00000000 --- a/src/config/variables.ts +++ /dev/null @@ -1,26 +0,0 @@ -import vars from "../data/variables.json"; - -export const { - VERSION, - RUNNING_IN_DOCKER, - TRUSTED_PROXIES, - HA_MASTER, - HA_MASTER_IP, - HA_NODE, - HA_UNSAFE, - DISCORD_WEBHOOK_URL, - EMAIL_SENDER, - EMAIL_RECIPIENT, - EMAIL_PASSWORD, - EMAIL_SERVICE, - PUSHBULLET_ACCESS_TOKEN, - PUSHOVER_USER_KEY, - PUSHOVER_API_TOKEN, - SLACK_WEBHOOK_URL, - TELEGRAM_BOT_TOKEN, - TELEGRAM_CHAT_ID, - WHATSAPP_API_URL, - WHATSAPP_RECIPIENT, - AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT, - LOG_LEVEL, -} = vars; diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts deleted file mode 100644 index 905e39c9..00000000 --- a/src/controllers/auth.ts +++ /dev/null @@ -1,64 +0,0 @@ -import fs from "fs/promises"; -import logger from "../utils/logger"; -const passwordFile: string = "./src/data/password.json"; -const passwordBool: string = "./src/data/usePassword.txt"; - -async function authEnabled(): Promise { - let isAuthEnabled: boolean = false; - let data: string = ""; - try { - data = await fs.readFile(passwordBool, "utf8"); - isAuthEnabled = data.trim() === "true"; - return isAuthEnabled; - } catch (error: unknown) { - logger.error("Error reading file: ", error as Error); - return isAuthEnabled; - } -} - -async function readPasswordFile() { - let data: string = ""; - try { - data = await fs.readFile(passwordFile, "utf8"); - return data; - } catch (error: unknown) { - logger.error("Could not read saved password: ", error as Error); - return data; - } -} - -async function writePasswordFile(passwordData: string) { - try { - await fs.writeFile(passwordFile, passwordData); - setTrue(); - logger.debug("Authentication enabled"); - return "Authentication enabled"; - } catch (error: unknown) { - logger.error("Error writing password file:", error as Error); - return error; - } -} - -async function setTrue() { - try { - await fs.writeFile(passwordBool, "true", "utf8"); - logger.info(`Enabled authentication`); - return; - } catch (error: unknown) { - logger.error("Error writing to the file:", error as Error); - return; - } -} - -async function setFalse() { - try { - await fs.writeFile(passwordBool, "false", "utf8"); - logger.info(`Disabled authentication`); - return; - } catch (error: unknown) { - logger.error("Error writing to the file:", error as Error); - return; - } -} - -export { authEnabled, readPasswordFile, writePasswordFile, setFalse }; diff --git a/src/controllers/containerController.ts b/src/controllers/containerController.ts deleted file mode 100644 index 2883dad9..00000000 --- a/src/controllers/containerController.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { getDockerClient } from "../utils/dockerClient"; -import logger from "../utils/logger"; -import { Request, Response } from "express"; -import { createResponseHandler } from "../handlers/response"; - -const getContainers = async (req: Request, res: Response): Promise => { - const ResponseHandler = createResponseHandler(res); - const host: string = (req.query.host as string) || "local"; - - logger.info(`Fetching containers from host: ${host}`); - - try { - const docker = getDockerClient(host); - const containers = await docker.listContainers(); - - return ResponseHandler.rawData( - containers, - `Fetched containers from ${host}`, - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } -}; - -const getContainerStats = async ( - containerID: string, - containerHost: string, - res: Response, -): Promise => { - logger.info( - `Fetching stats for container: ${containerID} from host: ${containerHost}`, - ); - const ResponseHandler = createResponseHandler(res); - - try { - const docker = getDockerClient(containerHost); - const container = docker.getContainer(containerID); - const stats = await container.stats({ stream: false }); - - return ResponseHandler.rawData( - stats, - `Successfully fetched stats for container: ${containerID} from host: ${containerHost}`, - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } -}; - -export default { - getContainers, - getContainerStats, -}; diff --git a/src/controllers/databaseMigration.ts b/src/controllers/databaseMigration.ts deleted file mode 100644 index 45f88d12..00000000 --- a/src/controllers/databaseMigration.ts +++ /dev/null @@ -1,20 +0,0 @@ -import db from "../config/db"; -import logger from "../utils/logger"; - -function clearOldEntries(): void { - const twentyFourHoursAgo: number = Date.now() - 24 * 60 * 60 * 1000; - - db.run( - `DELETE FROM data WHERE createdAt < ?`, - [twentyFourHoursAgo], - (err: Error | null) => { - if (err) { - logger.error("Error deleting old entries:", err.message); - throw new Error("Database cleanup failed"); - } - logger.info("Old entries cleared successfully"); - }, - ); -} - -export default clearOldEntries; diff --git a/src/controllers/fetchData.ts b/src/controllers/fetchData.ts deleted file mode 100644 index 06e52a93..00000000 --- a/src/controllers/fetchData.ts +++ /dev/null @@ -1,76 +0,0 @@ -import db from "../config/db"; -import { fetchAllContainers } from "../utils/containerService"; -import logger from "../utils/logger"; -import fs from "fs"; -import { atomicWrite } from "../utils/atomicWrite"; -const filePath = "./src/data/states.json"; - -let previousState: { [key: string]: string } = {}; - -interface Container { - name: string; - id: string; - state: string; - hostName: string; -} - -interface AllContainerData { - [host: string]: Container[] | { error: string }; -} - -const fetchData = async (): Promise => { - try { - const allContainerData: AllContainerData = - (await fetchAllContainers()) || {}; - - db.run( - `INSERT INTO data (info) VALUES (?)`, - [JSON.stringify(allContainerData)], - function (error) { - if (error) { - logger.error("Error inserting data:", error); - return; - } - logger.info(`Data inserted with ID: ${this.lastID}`); - }, - ); - - const containerStatus: AllContainerData = {}; - - Object.keys(allContainerData).forEach((host) => { - const containers = allContainerData[host]; - - // Handle if the containers are an array, otherwise handle the error - if (Array.isArray(containers)) { - containerStatus[host] = containers.map((container: Container) => ({ - name: container.name, - id: container.id, - state: container.state, - hostName: container.hostName, - })); - } else { - // If there's an error, handle it separately - containerStatus[host] = { error: "Error fetching containers" }; - } - }); - - if (fs.existsSync(filePath)) { - const fileData = fs.readFileSync(filePath, "utf8"); - previousState = fileData ? JSON.parse(fileData) : {}; - } - - // Compare previous and current state - if (JSON.stringify(previousState) !== JSON.stringify(containerStatus)) { - atomicWrite(filePath, JSON.stringify(containerStatus, null, 2)); - logger.info(`Container states saved to ${filePath}`); - // TODO: Add logic + notification levels per service - } else { - logger.info("No state change detected, notifications not triggered."); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -}; - -export default fetchData; diff --git a/src/controllers/frontendConfiguration.ts b/src/controllers/frontendConfiguration.ts deleted file mode 100644 index ed4e59dd..00000000 --- a/src/controllers/frontendConfiguration.ts +++ /dev/null @@ -1,297 +0,0 @@ -import fs from "fs"; -import logger from "../utils/logger"; -const dataPath: string = "./src/data/frontendConfiguration.json"; -const expression: string = - "https?://(www.)?[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_+.~#?&//=]*)"; -const regex = new RegExp(expression); -import { FrontendConfig } from "../typings/frontendConfig"; - -/////////////////////////////////////////////////////////////// -// Hide Containers: -async function hideContainer(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - data[containerIndex].hidden = true; - await saveData(data); - } else { - data.push({ name: containerName, hidden: true }); - await saveData(data); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function unhideContainer(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - delete data[containerIndex].hidden; - await saveData(data); - cleanupData(); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -/////////////////////////////////////////////////////////////// -// Tag containers -async function addTagToContainer(containerName: string, tag: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - if (!data[containerIndex].tags) { - data[containerIndex].tags = []; - } - data[containerIndex].tags.push(tag); - await saveData(data); - } else { - data.push({ name: containerName, tags: [tag] }); - await saveData(data); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function removeTagFromContainer(containerName: string, tag: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1 && data[containerIndex].tags) { - data[containerIndex].tags = data[containerIndex].tags.filter( - (t) => t !== tag, - ); - await saveData(data); - cleanupData(); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -/////////////////////////////////////////////////////////////// -// Pin containers -async function pinContainer(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - data[containerIndex].pinned = true; - await saveData(data); - } else { - data.push({ name: containerName, pinned: true }); - await saveData(data); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function unpinContainer(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - delete data[containerIndex].pinned; - await saveData(data); - cleanupData(); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -/////////////////////////////////////////////////////////////// -// Add/remove link from containers -async function setLink(containerName: string, link: string) { - if (link.match(regex)) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - data[containerIndex].link = `${link}`; - await saveData(data); - } else { - data.push({ name: containerName, link: `${link}` }); - await saveData(data); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } - } else { - logger.error(`Provided link is not valid: ${link}`); - throw new Error(`Provided link is not valid: ${link}`); - } -} - -async function removeLink(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - delete data[containerIndex].link; - await saveData(data); - cleanupData(); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -/////////////////////////////////////////////////////////////// -// Add/remove icon from containers -async function setIcon(containerName: string, icon: string, custom: boolean) { - try { - const data = await readData(); - const containerIndex: number = data.findIndex( - (container) => container.name === containerName, - ); - - if (custom === true) { - if (containerIndex !== -1) { - data[containerIndex].icon = `custom/${icon}`; - await saveData(data); - } else { - data.push({ name: containerName, icon: `custom/${icon}` }); - await saveData(data); - } - } else if (containerIndex !== -1) { - data[containerIndex].icon = `${icon}`; - await saveData(data); - } else { - data.push({ name: containerName, icon: `${icon}` }); - await saveData(data); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function removeIcon(containerName: string) { - try { - const data = await readData(); - const containerIndex = data.findIndex( - (container) => container.name === containerName, - ); - - if (containerIndex !== -1) { - delete data[containerIndex].icon; - await saveData(data); - cleanupData(); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -/////////////////////////////////////////////////////////////// -// Data specific functionss -async function readData() { - try { - const data: FrontendConfig = JSON.parse( - await fs.promises.readFile(dataPath, "utf-8"), - ); - return data; - } catch (error: unknown) { - console.error(`Error while reading ${dataPath}: ${error as Error}`); - if (error as Error) { - await saveData([]); - return []; - } else { - throw error; - } - } -} - -async function saveData(data: FrontendConfig) { - try { - await fs.promises.writeFile( - dataPath, - JSON.stringify(data, null, 2), - "utf-8", - ); - logger.info("Succesfully wrote to file"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function cleanupData() { - try { - const data = await readData(); - let cleanedData: FrontendConfig = []; - - if (data && Array.isArray(data)) { - cleanedData = data.filter((container) => { - // Filter out containers with empty "tags" or containers with only one property (name) - if ( - container.tags && - Array.isArray(container.tags) && - container.tags.length === 0 - ) { - delete container.tags; - } - return Object.keys(container).length > 1; - }); - } - - await saveData(cleanedData); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -export { - hideContainer, - unhideContainer, - addTagToContainer, - removeTagFromContainer, - pinContainer, - unpinContainer, - setLink, - removeLink, - setIcon, - removeIcon, -}; diff --git a/src/controllers/highAvailability.ts b/src/controllers/highAvailability.ts deleted file mode 100644 index 45db9d7b..00000000 --- a/src/controllers/highAvailability.ts +++ /dev/null @@ -1,285 +0,0 @@ -import logger from "../utils/logger"; -import fs from "fs"; -import chokidar from "chokidar"; -import path from "path"; -import { promisify } from "util"; -import { - HA_UNSAFE, - HA_MASTER, - HA_MASTER_IP, - HA_NODE, -} from "../config/variables"; -import { atomicWrite } from "../utils/atomicWrite"; -import { HighAvailabilityConfig, HaNodeConfig, NodeCache } from "../typings/ha"; - -const sleep = promisify(setTimeout); - -const haMasterPath: string = "./src/data/highAvailability.json"; -const haNodePath: string = "./src/data/haNode.json"; -const nodeCachePath: string = "./src/data/nodeCache.json"; -const useUnsafeConnection: boolean = JSON.parse(HA_UNSAFE || "false"); -const lockFilePath: string = "./src/data/ha.lock"; - -const configFiles: string[] = [ - "./src/data/dockerConfig.json", - "./src/data/states.json", - "./src/data/template.json", - "./src/data/frontendConfiguration.json", - "./src/data/nodeCache.json", - "./src/data/usePassword.txt", - "./src/data/password.json", -]; - -const MAX_RETRIES = 10; -const BASE_DELAY_MS = 100; - -async function acquireLock(): Promise { - let retryCount = 0; - - while (fs.existsSync(lockFilePath)) { - if (retryCount >= MAX_RETRIES) { - throw new Error( - "Failed to acquire lock: maximum retry attempts exceeded", - ); - } - - const backoffMs = BASE_DELAY_MS * Math.pow(2, retryCount); - const jitter = Math.random() * 0.3 * backoffMs; - const delayMs = backoffMs + jitter; - - logger.warn( - `Lock file exists, waiting ${Math.round(delayMs)}ms before retry ${retryCount + 1}/${MAX_RETRIES}...`, - ); - await sleep(delayMs); - retryCount++; - } - - try { - atomicWrite(lockFilePath, "locked", { exclusive: true }); - logger.debug("Lock acquired."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function releaseLock(): Promise { - try { - if (fs.existsSync(lockFilePath)) { - await fs.promises.unlink(lockFilePath); - logger.debug("Lock released."); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -async function writeConfig( - data: HighAvailabilityConfig | NodeCache | HaNodeConfig, - filePath: string, -): Promise { - await acquireLock(); - try { - logger.debug(`Writing ${filePath}`); - const dirPath: string = path.dirname(filePath); - await fs.promises.mkdir(dirPath, { recursive: true }); - - const jsonData = JSON.stringify(data, null, 2); - await fs.promises.writeFile(filePath, jsonData); - - logger.debug(`${filePath} has been written.`); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } finally { - await releaseLock(); - } -} - -async function readConfig(): Promise { - await acquireLock(); - try { - logger.debug("Reading HA-Config"); - const data: HighAvailabilityConfig = JSON.parse( - fs.readFileSync(haMasterPath, "utf-8"), - ); - return data; - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return null; - } finally { - await releaseLock(); - } -} - -async function prepareFilesForSync(): Promise> { - const fileData: Record = {}; - try { - for (const filePath of configFiles) { - const content = await fs.promises.readFile(filePath, "utf-8"); - fileData[filePath] = content; - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } - return fileData; -} - -async function checkApiReachable(node: string): Promise { - const nodeUrl = - useUnsafeConnection === true - ? `http://${node}/api/status` - : `https://${node}/api/status`; - - logger.info(`Checking node (${nodeUrl}) reachability`); - - try { - const response = await fetch(nodeUrl); - if (!response.ok) { - logger.error(`Failed to reach node ${node}. Status: ${response.status}`); - return false; - } - - const data = await response.json(); - if (data.ApiReachable as boolean) { - logger.info(`Node ${node} is reachable.`); - return true; - } else { - logger.error(`Node ${node} is not reachable. ApiReachable: false`); - return false; - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return false; - } -} - -async function synchronizeFilesWithNodes(): Promise { - const haConfig = await readConfig(); - - if (!haConfig || !haConfig.master || haConfig.nodes.length === 0) { - logger.warn("No slave nodes to synchronize with."); - return; - } - - const files = await prepareFilesForSync(); - - for (const node of haConfig.nodes) { - if (!(await checkApiReachable(node))) { - logger.warn( - `Skipping file sync with ${node} due to connectivity issues.`, - ); - continue; // Skip synchronization if the node is unreachable - } - - const nodeUrl = - useUnsafeConnection === true - ? `http://${node}/ha/sync` - : `https://${node}/ha/sync`; - - logger.info(`Synchronizing files with node: ${node}`); - - const response = await fetch(nodeUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ files }), - }); - - if (response.ok) { - logger.info(`Files synchronized successfully with node: ${node}`); - } else { - logger.error( - `Failed to synchronize files with node ${node}. Status: ${response.status}`, - ); - } - } -} - -function monitorConfigFiles(): void { - const watcher = chokidar.watch(configFiles, { persistent: true }); - - watcher - .on("change", async (filePath) => { - logger.info(`File changed: ${filePath}. Initiating synchronization.`); - await synchronizeFilesWithNodes(); - }) - .on("error", (error) => { - logger.error(`Error watching files: ${(error as Error).message}`); - }); - - logger.info("Started monitoring configuration files for changes."); -} - -async function startMasterNode() { - if (HA_MASTER == "true") { - if (!HA_MASTER_IP) { - logger.error( - "Master's IP is not set, please set the HA_MASTER_IP variable (example: 10.0.0.4:9876)", - ); - } else { - const haNodeConfig: HaNodeConfig = { - master: HA_MASTER_IP, - }; - const haConfig: HighAvailabilityConfig = { - active: true, - master: true, - nodes: HA_NODE ? HA_NODE.split(",").map((node) => node.trim()) : [], - }; - - const nodeCache: NodeCache = HA_NODE - ? HA_NODE.split(",").reduce((cache, node, index) => { - const [ip, port] = node.trim().split(":"); - if (ip && port) { - cache[`node-${index + 1}`] = { ip, port: parseInt(port, 10) }; - } - return cache; - }, {} as NodeCache) - : {}; - - logger.debug("Writing HA-Config(s)"); - await writeConfig(haConfig, haMasterPath); - await writeConfig(haNodeConfig, haNodePath); - await writeConfig(nodeCache, nodeCachePath); - - logger.info("Running startup sync..."); - await synchronizeFilesWithNodes(); - logger.info("Watching config files in ./data"); - monitorConfigFiles(); - } - } else { - logger.info("This is a slave node"); - } -} - -async function ensureFileExists( - filePath: string, - content: string, -): Promise { - await acquireLock(); - try { - const dirPath = path.dirname(filePath); - await fs.promises.mkdir(dirPath, { recursive: true }); - await fs.promises.writeFile(filePath, content, { flag: "w" }); - logger.info(`File updated: ${filePath}`); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } finally { - await releaseLock(); - } -} - -export { - HighAvailabilityConfig, - writeConfig, - readConfig, - prepareFilesForSync, - synchronizeFilesWithNodes, - monitorConfigFiles, - startMasterNode, - ensureFileExists, -}; diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts deleted file mode 100644 index 0ece9553..00000000 --- a/src/controllers/notificationController.ts +++ /dev/null @@ -1,60 +0,0 @@ -import notify from "../utils/notifications/_notify"; -import logger from "../utils/logger"; -import { - DISCORD_WEBHOOK_URL, - EMAIL_SENDER, - EMAIL_RECIPIENT, - EMAIL_PASSWORD, - EMAIL_SERVICE, - PUSHBULLET_ACCESS_TOKEN, - PUSHOVER_USER_KEY, - PUSHOVER_API_TOKEN, - SLACK_WEBHOOK_URL, - TELEGRAM_BOT_TOKEN, - TELEGRAM_CHAT_ID, - WHATSAPP_API_URL, - WHATSAPP_RECIPIENT, -} from "../config/variables"; - -const notificationTypes = { - discord: !!DISCORD_WEBHOOK_URL, - email: !!(EMAIL_SENDER && EMAIL_RECIPIENT && EMAIL_PASSWORD && EMAIL_SERVICE), - pushbullet: !!PUSHBULLET_ACCESS_TOKEN, - pushover: !!(PUSHOVER_API_TOKEN && PUSHOVER_USER_KEY), - slack: !!SLACK_WEBHOOK_URL, - telegram: !!(TELEGRAM_BOT_TOKEN && TELEGRAM_CHAT_ID), - whatsapp: !!(WHATSAPP_API_URL && WHATSAPP_RECIPIENT), -}; - -async function sendNotification(containerId: string) { - if (notificationTypes.discord) { - logger.debug(`Sending notification via discord (${containerId})`); - notify("discord", containerId); - } - if (notificationTypes.email) { - logger.debug(`Sending notification via E-Mail (${containerId})`); - notify("email", containerId); - } - if (notificationTypes.pushbullet) { - logger.debug(`Sending notification via Pushbullet (${containerId})`); - notify("pushbullet", containerId); - } - if (notificationTypes.pushover) { - logger.debug(`Sending notification via Pushover (${containerId})`); - notify("pushover", containerId); - } - if (notificationTypes.slack) { - logger.debug(`Sending notification via Slack (${containerId})`); - notify("slack", containerId); - } - if (notificationTypes.telegram) { - logger.debug(`Sending notification via Telegram (${containerId})`); - notify("slack", containerId); - } - if (notificationTypes.whatsapp) { - logger.debug(`Sending notification via Pushbullet (${containerId})`); - notify("whatsapp", containerId); - } -} - -export default sendNotification; diff --git a/src/controllers/proxy.ts b/src/controllers/proxy.ts deleted file mode 100644 index c091590a..00000000 --- a/src/controllers/proxy.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Application } from "express"; -import logger from "../utils/logger"; -import { TRUSTED_PROXIES } from "../config/variables"; - -export default function trustedProxies(app: Application) { - const trusted: string = TRUSTED_PROXIES; - - if (!trusted) { - logger.warn( - "No trusted Proxy configured, if ran behind a proxy please configure it according to the docs", - ); - } else { - app.set("trust proxy", trusted); - } -} diff --git a/src/controllers/scheduler.ts b/src/controllers/scheduler.ts deleted file mode 100644 index db450d95..00000000 --- a/src/controllers/scheduler.ts +++ /dev/null @@ -1,91 +0,0 @@ -import fetchData from "./fetchData"; -import logger from "../utils/logger"; -import db from "../config/db"; -const regex = /(\d{1,5})([smh])/g; - -let fetchInterval = 5 * 60 * 1000; // Fetch data every 5 minutes by default -const cleanupInterval = 24 * 60 * 60 * 1000; // every 24hrs -let intervalId: NodeJS.Timeout; - -const scheduleFetch = () => { - try { - fetchData(); - cleanupOldEntries(); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } - - intervalId = setInterval(() => { - logger.info( - `Fetching data at interval of ${fetchInterval / 1000} seconds.`, - ); - fetchData(); - }, fetchInterval); - - setInterval(() => { - cleanupOldEntries(); - }, cleanupInterval); - - logger.info(`Data fetching scheduled every ${fetchInterval / 1000} seconds.`); - logger.info("Old entries cleanup scheduled every 24 hours."); - - // Additional 20-second interval to log process exit listeners, if any - setInterval(() => { - const exitListeners = process.listeners("exit"); - - if (exitListeners.length > 0) { - logger.info(`Exit listeners detected: ${exitListeners}`); - } - }, 20000); -}; - -const setFetchInterval = (newInterval: number) => { - if (intervalId) { - clearInterval(intervalId); - logger.info("Cleared existing fetch interval."); - } - fetchInterval = newInterval; - scheduleFetch(); - logger.info(`Fetch interval updated to ${fetchInterval / 1000} seconds.`); -}; - -const parseInterval = (interval: string) => { - const timeUnits: { [key: string]: number } = { - s: 1000, - m: 60 * 1000, - h: 60 * 60 * 1000, - }; - - let totalMilliseconds = 0; - let match; - - while ((match = regex.exec(interval))) { - const value = parseInt(match[1], 10); - const unit = match[2]; - totalMilliseconds += value * timeUnits[unit]; - } - - return totalMilliseconds; -}; - -const getCurrentSchedule = () => { - return { - interval: fetchInterval / 1000, - }; -}; - -const cleanupOldEntries = async () => { - const twentyFourHoursAgo = new Date( - Date.now() - 24 * 60 * 60 * 1000, - ).toISOString(); - try { - db.run("DELETE FROM data WHERE timestamp < ?", twentyFourHoursAgo, Error); - logger.info("Old entries cleared from the database."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -}; - -export { scheduleFetch, setFetchInterval, parseInterval, getCurrentSchedule }; diff --git a/src/core/database/helper.ts b/src/core/database/helper.ts new file mode 100644 index 00000000..3bea0446 --- /dev/null +++ b/src/core/database/helper.ts @@ -0,0 +1,17 @@ +import { logger } from "../utils/logger"; + +export function executeDbOperation( + label: string, + operation: () => T, + validate?: () => void +): T { + const startTime = Date.now(); + logger.debug(`__task__ __db__ ${label} �3`); + if (validate) { + validate(); + } + const result = operation(); + const duration = Date.now() - startTime; + logger.debug(`__task__ __db__ ${label} �4f (${duration}ms)`); + return result; +} \ No newline at end of file diff --git a/src/core/database/repository.ts b/src/core/database/repository.ts new file mode 100644 index 00000000..56543cf2 --- /dev/null +++ b/src/core/database/repository.ts @@ -0,0 +1,565 @@ +import { executeDbOperation } from "./helper"; +import Database from "bun:sqlite"; +import { logger } from "~/core/utils/logger"; +import { relayController } from "~/core/docker/relay-controller"; +import type { DockerHost, HostStats } from "~/typings/docker"; +import type { stacks_config } from "~/typings/database"; + +const db = new Database("dockstatapi.db"); +db.exec("PRAGMA journal_mode = WAL;"); + +export const dbFunctions = { + init() { + const startTime = Date.now(); + db.exec(` + CREATE TABLE IF NOT EXISTS backend_log_entries ( + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + level TEXT, + message TEXT, + file TEXT, + line NUMBER + ); + + CREATE TABLE IF NOT EXISTS stacks_config ( + name TEXT PRIMARY KEY, + version INTEGER, + custom BOOLEAN, + source TEXT, + container_count INTEGER, + stack_prefix TEXT, + automatic_reboot_on_error BOOLEAN, + image_updates BOOLEAN + ); + + CREATE TABLE IF NOT EXISTS docker_hosts ( + name TEXT, + url TEXT, + secure BOOLEAN + ); + + CREATE TABLE IF NOT EXISTS host_stats ( + hostId TEXT PRIMARY KEY, + dockerVersion TEXT, + apiVersion TEXT, + os TEXT, + architecture TEXT, + totalMemory INTEGER, + totalCPU INTEGER, + labels TEXT, + containers INTEGER, + containersRunning INTEGER, + containersStopped INTEGER, + containersPaused INTEGER, + images INTEGER + ); + + CREATE TABLE IF NOT EXISTS container_stats ( + id TEXT, + hostId TEXT, + name TEXT, + image TEXT, + status TEXT, + state TEXT, + cpu_usage FLOAT, + memory_usage FLOAT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP + ); + + CREATE TABLE IF NOT EXISTS config ( + polling_rate NUMBER, + keep_data_for NUMBER, + fetching_interval NUMBER + ); + `); + + logger.info("Starting server..."); + + + /* + * Default values: + * - Websocket polling interval 5 seconds + * - Data retention value for the database (logs and container stats) 7 days + * - Data fetcher for the Database: 5 minutes + */ + const configRow = db + .prepare(`SELECT COUNT(*) AS count FROM config`) + .get() as { count: number }; + if (configRow.count === 0) { + logger.debug("Initializing default config"); + const stmt = db.prepare( + ` + INSERT INTO config (polling_rate, keep_data_for, fetching_interval) VALUES (5, 7, 5) + `, + ); + stmt.run(); + } + + const hostRow = db + .prepare(`SELECT COUNT(*) AS count FROM docker_hosts WHERE name = ?`) + .get("Localhost") as { count: number }; + if (hostRow.count === 0) { + logger.debug("Initializing default docker host (Localhost)"); + const stmt = db.prepare( + ` + INSERT INTO docker_hosts (name, url, secure) VALUES (?, ?, ?) + `, + ); + stmt.run("Localhost", "localhost:2375", false); + } + logger.debug("__task__ __db__ Initializing Database ⏳") + const duration = Date.now() - startTime; + logger.debug(`__task__ __db__ Initializing Database ✔️ (${duration}ms)`); + }, + + addDockerHost(hostId: string, url: string, secure: boolean) { + return executeDbOperation( + "Add Docker Host", + () => { + const stmt = db.prepare(` + INSERT INTO docker_hosts (name, url, secure) + VALUES (?, ?, ?) + `); + return stmt.run(hostId, url, secure); + }, + () => { + if ( + typeof hostId !== "string" || + typeof url !== "string" || + typeof secure !== "boolean" + ) { + logger.error("Invalid parameter types for addDockerHost"); + throw new TypeError("Invalid parameter types for addDockerHost"); + } + } + ); + }, + + getDockerHosts(): DockerHost[] { + return executeDbOperation( + "Get Docker Hosts", + () => { + const stmt = db.prepare(` + SELECT name, url, secure + FROM docker_hosts + ORDER BY name DESC + `); + const data = stmt.all(); + return data as DockerHost[]; + }, + () => { } + ); + }, + + addLogEntry: ( + level: string, + message: string, + file_name: string, + line: number, + ) => { + if ( + typeof level !== "string" || + typeof message !== "string" || + typeof file_name !== "string" || + typeof line !== "number" + ) { + logger.crit("Invalid parameter types for addLogEntry"); + throw new TypeError("Invalid parameter types for addLogEntry"); + } + + const stmt = db.prepare(` + INSERT INTO backend_log_entries (level, message, file, line) + VALUES (?, ?, ?, ?) + `); + return stmt.run(level, message, file_name, line); + }, + + getAllLogs() { + return executeDbOperation( + "Get All Logs", + () => { + const stmt = db.prepare(` + SELECT timestamp, level, message, file, line + FROM backend_log_entries + ORDER BY timestamp DESC + `); + const data = stmt.all(); + return data; + }, + () => { } + ); + }, + + getLogsByLevel(level: string) { + return executeDbOperation( + "Get Logs By Level", + () => { + const stmt = db.prepare(` + SELECT timestamp, level, message, file, line + FROM backend_log_entries + WHERE level = ? + ORDER BY timestamp DESC + `); + const data = stmt.all(level); + return data; + }, + () => { + if (typeof level !== "string") { + logger.error("Level parameter must be a string"); + throw new TypeError("Level parameter must be a string"); + } + } + ); + }, + + updateDockerHost(name: string, url: string, secure: boolean) { + return executeDbOperation( + "Update Docker Host", + () => { + const stmt = db.prepare(` + UPDATE docker_hosts + SET url = ?, secure = ? + WHERE name = ? + `); + const data = stmt.run(url, secure, name); + return data; + }, + () => { + if ( + typeof name !== "string" || + typeof url !== "string" || + typeof secure !== "boolean" + ) { + logger.error("Invalid parameter types for updateDockerHost"); + throw new TypeError("Invalid parameter types for updateDockerHost"); + } + } + ); + }, + + deleteDockerHost(name: string) { + return executeDbOperation( + "Delete Docker Host", + () => { + const stmt = db.prepare(` + DELETE FROM docker_hosts + WHERE name = ? + `); + const data = stmt.run(name); + return data; + }, + () => { + if (typeof name !== "string") { + logger.error("Invalid parameter type for deleteDockerHost"); + throw new TypeError("Name parameter must be a string"); + } + } + ); + }, + + clearAllLogs() { + return executeDbOperation( + "Clear All Logs", + () => { + const stmt = db.prepare(` + DELETE FROM backend_log_entries + `); + const data = stmt.run(); + return data; + }, + () => { } + ); + }, + + clearLogsByLevel(level: string) { + return executeDbOperation( + "Clear Logs By Level", + () => { + const stmt = db.prepare(` + DELETE FROM backend_log_entries + WHERE level = ? + `); + const data = stmt.run(level); + return data; + }, + () => { + if (typeof level !== "string") { + logger.error("Invalid parameter type for clearLogsByLevel"); + throw new TypeError("Level parameter must be a string"); + } + } + ); + }, + + updateConfig( + polling_rate: number, + fetching_interval: number, + keep_data_for: number + ) { + return executeDbOperation( + "Update Config", + () => { + const stmt = db.prepare(` + UPDATE config + SET polling_rate = ?, + fetching_interval = ?, + keep_data_for = ? + `); + const data = stmt.run(polling_rate, fetching_interval, keep_data_for); + return data; + }, + () => { + if ( + typeof polling_rate !== "number" || + typeof fetching_interval !== "number" || + typeof keep_data_for !== "number" + ) { + logger.error("Invalid parameter types for updateConfig"); + throw new TypeError("Invalid parameter types for updateConfig"); + } + } + ); + }, + + getConfig() { + return executeDbOperation( + "Get Config", + () => { + const stmt = db.prepare(` + SELECT polling_rate, keep_data_for, fetching_interval + FROM config + `); + const data = stmt.all(); + return data; + }, + () => { } + ); + }, + + deleteOldData(days: number) { + return executeDbOperation( + "Delete Old Data", + () => { + const deleteContainerStmt = db.prepare(` + DELETE FROM container_stats + WHERE timestamp < datetime('now', '-' || ? || ' days') + `); + deleteContainerStmt.run(days); + + const deleteLogsStmt = db.prepare(` + DELETE FROM backend_log_entries + WHERE timestamp < datetime('now', '-' || ? || ' days') + `); + deleteLogsStmt.run(days); + }, + () => { + if (typeof days !== "number") { + logger.error("Invalid parameter type for deleteOldData"); + throw new TypeError("Days parameter must be a number"); + } + } + ); + }, + + addContainerStats( + id: string, + hostId: string, + name: string, + image: string, + status: string, + state: string, + cpu_usage: number, + memory_usage: number + ) { + return executeDbOperation( + "Add Container Stats", + () => { + const stmt = db.prepare(` + INSERT INTO container_stats (id, hostId, name, image, status, state, cpu_usage, memory_usage) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `); + const data = stmt.run( + id, + hostId, + name, + image, + status, + state, + cpu_usage, + memory_usage + ); + return data; + }, + () => { + if ( + typeof id !== "string" || + typeof hostId !== "string" || + typeof name !== "string" || + typeof image !== "string" || + typeof status !== "string" || + typeof state !== "string" || + typeof cpu_usage !== "number" || + typeof memory_usage !== "number" + ) { + logger.error("Invalid parameter types for addContainerStats"); + throw new TypeError("Invalid parameter types for addContainerStats"); + } + } + ); + }, + + updateHostStats(stats: HostStats) { + return executeDbOperation( + "Update Host Stats", + () => { + const labelsJson = JSON.stringify(stats.labels); + const stmt = db.prepare(` + INSERT INTO host_stats ( + hostId, + dockerVersion, + apiVersion, + os, + architecture, + totalMemory, + totalCPU, + labels, + containers, + containersRunning, + containersStopped, + containersPaused, + images + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(hostId) DO UPDATE SET + dockerVersion = excluded.dockerVersion, + apiVersion = excluded.apiVersion, + os = excluded.os, + architecture = excluded.architecture, + totalMemory = excluded.totalMemory, + totalCPU = excluded.totalCPU, + labels = excluded.labels, + containers = excluded.containers, + containersRunning = excluded.containersRunning, + containersStopped = excluded.containersStopped, + containersPaused = excluded.containersPaused, + images = excluded.images; + `); + const data = stmt.run( + stats.hostId, + stats.dockerVersion, + stats.apiVersion, + stats.os, + stats.architecture, + stats.totalMemory, + stats.totalCPU, + labelsJson, + stats.containers, + stats.containersRunning, + stats.containersStopped, + stats.containersPaused, + stats.images + ); + return data; + }, + () => { } + ); + }, + + addStack(stack_config: stacks_config) { + return executeDbOperation( + "Add Stack Config", + () => { + const stmt = db.prepare(` + INSERT INTO stacks_config ( + name, + version, + custom, + source, + container_count, + stack_prefix, + automatic_reboot_on_error, + image_updates + ) + VALUES(?, ?, ?, ?, ?, ?, ?, ?) + `); + const data = stmt.run( + stack_config.name, + stack_config.version, + stack_config.custom, + stack_config.source, + stack_config.container_count, + stack_config.stack_prefix, + stack_config.automatic_reboot_on_error, + stack_config.image_updates + ); + relayController.stackAdded(); + return data; + }, + () => { } + ); + }, + + getStacks() { + return executeDbOperation( + "Get Stacks", + () => { + const stmt = db.prepare(` + SELECT name, version, custom, source, container_count, stack_prefix, automatic_reboot_on_error, image_updates + FROM stacks_config + ORDER BY name DESC + `); + const data = stmt.all(); + return data; + }, + () => { } + ); + }, + + deleteStack(name: string) { + return executeDbOperation( + "Delete Stack", + () => { + const stmt = db.prepare(` + DELETE FROM stacks_config + WHERE name = ?; + `); + const data = stmt.run(name); + relayController.stackDeleted(); + return data; + }, + () => { } + ); + }, + + updateStack(stack_config: stacks_config) { + return executeDbOperation( + "Update Stack", + () => { + const stmt = db.prepare(` + UPDATE stacks_config + SET + version = ?, + custom = ?, + source = ?, + container_count = ?, + stack_prefix = ?, + automatic_reboot_on_error = ?, + image_updates = ? + WHERE name = ?; + `); + const data = stmt.run( + stack_config.version, + stack_config.custom, + stack_config.source, + stack_config.container_count, + stack_config.stack_prefix, + stack_config.automatic_reboot_on_error, + stack_config.image_updates, + stack_config.name + ); + relayController.stackUpdated(); + return data; + }, + () => { } + ); + } +}; diff --git a/src/core/docker/client.ts b/src/core/docker/client.ts new file mode 100644 index 00000000..ee0d7147 --- /dev/null +++ b/src/core/docker/client.ts @@ -0,0 +1,61 @@ +import type { DockerHost } from "~/typings/docker"; +import Docker from "dockerode"; +import { logger } from "~/core/utils/logger"; + +async function fileExists(path: string): Promise { + try { + return await Bun.file(path).exists(); + } catch (error) { + return false; + } +} + +export const getDockerClient = (host: DockerHost): Docker => { + try { + const inputUrl = host.url.includes("://") ? host.url : `${host.secure ? "https" : "http"}://${host.url}`; + const parsedUrl = new URL(inputUrl); + const hostAddress = parsedUrl.hostname; + let port = parsedUrl.port ? parseInt(parsedUrl.port) : (host.secure ? 2376 : 2375); + + if (isNaN(port) || port < 1 || port > 65535) { + throw new Error("Invalid port number in Docker host URL"); + } + + return new Docker({ + protocol: host.secure ? "https" : "http", + host: hostAddress, + port, + version: "v1.41", + // TODO: Add TLS configuration if needed + }); + } catch (error) { + logger.error("Invalid Docker host URL configuration:", error); + throw new Error("Invalid Docker host configuration"); + } +}; + +export const stackClient = async (): Promise => { + const socketPath = "/var/run/docker.sock"; + try { + if (!(await fileExists(socketPath))) { + throw new Error("Docker socket not found at " + socketPath); + } + + const docker = new Docker({ + socketPath + }); + + const pingTimeout = 2000; + await Promise.race([ + docker.ping(), + new Promise((_, reject) => + setTimeout(() => reject(new Error("Ping timed out")), pingTimeout) + ) + ]); + + return docker; + } catch (error) { + logger.error(`Could not create Docker client for "${socketPath}" - ${error}`); + throw new Error("Failed to create Docker client for local Docker socket"); + } +}; diff --git a/src/core/docker/relay-controller.ts b/src/core/docker/relay-controller.ts new file mode 100644 index 00000000..db8b6bb5 --- /dev/null +++ b/src/core/docker/relay-controller.ts @@ -0,0 +1,13 @@ +// Import any function here, when any of the specifies functions is detected, it will run said function + +export const relayController = { + stackAdded() { + + }, + stackDeleted() { + + }, + stackUpdated() { + + } +} \ No newline at end of file diff --git a/src/core/docker/scheduler.ts b/src/core/docker/scheduler.ts new file mode 100644 index 00000000..e4adf9ce --- /dev/null +++ b/src/core/docker/scheduler.ts @@ -0,0 +1,115 @@ +import storeContainerData from "~/core/docker/store-container-stats"; +import { dbFunctions } from "~/core/database/repository"; +import { config } from "~/typings/database"; +import { logger } from "~/core/utils/logger"; +import storeHostData from "~/core/docker//store-host-stats"; + +function convertFromMinToMs(minutes: number): number { + return minutes * 60 * 1000; +} + +async function initialRun( + scheduleName: string, + scheduleFunction: Promise | void, + isAsync: boolean, +) { + try { + if (isAsync) { + await scheduleFunction; + } else { + scheduleFunction; + } + logger.info(`Startup run success for: ${scheduleName}`); + } catch (error) { + logger.error(`Startup run failed for ${scheduleName}, ${error as string}`); + } +} + +async function setSchedules() { + try { + const rawConfigData: unknown[] = dbFunctions.getConfig(); + const configData = rawConfigData[0]; + + if ( + !configData || + typeof (configData as config).keep_data_for !== "number" || + typeof (configData as config).fetching_interval !== "number" + ) { + logger.error("Invalid configuration data:", configData); + throw new Error("Invalid configuration data"); + } + + const { keep_data_for, fetching_interval } = configData as config; + + if (keep_data_for === undefined) { + const errMsg = "keep_data_for is undefined"; + logger.error(errMsg); + throw new Error(errMsg); + } + + if (fetching_interval === undefined) { + const errMsg = "fetching_interval is undefined"; + logger.error(errMsg); + throw new Error(errMsg); + } + + logger.info( + `Scheduling: Fetching container statistics every ${fetching_interval} minutes`, + ); + + logger.info( + `Scheduling: Updating host statistics every ${fetching_interval} minutes`, + ); + + logger.info( + `Scheduling: Cleaning up Database every hour and deleting data older then ${keep_data_for} days`, + ); + + // Schedule container data fetching + await initialRun("storeContainerData", storeContainerData(), true); + setInterval(async () => { + try { + logger.info("Task Start: Fetching container data."); + await storeContainerData(); + logger.info("Task End: Container data fetched successfully."); + } catch (error) { + logger.error("Error in fetching container data:", error); + } + }, convertFromMinToMs(fetching_interval)); + + // Schedule Host statistics updates + await initialRun("storeHostData", storeHostData(), true); + setInterval(async () => { + try { + logger.info("Task Start: Updating host stats."); + await storeHostData(); + logger.info("Task End: Updating host stats successfully."); + } catch (error) { + logger.error("Error in updating host stats:", error); + } + }, convertFromMinToMs(fetching_interval)); + + // Schedule database cleanup + await initialRun( + "dbFunctions.deleteOldData", + dbFunctions.deleteOldData(keep_data_for), + false, + ); + setInterval(() => { + try { + logger.info("Task Start: Cleaning up old database data."); + dbFunctions.deleteOldData(keep_data_for); + logger.info("Task End: Database cleanup completed."); + } catch (error) { + logger.error("Error in database cleanup task:", error); + } + }, convertFromMinToMs(60)); + + logger.info("Schedules have been set successfully."); + } catch (error) { + logger.error("Error setting schedules:", error); + throw error; + } +} + +export { setSchedules }; diff --git a/src/core/docker/store-container-stats.ts b/src/core/docker/store-container-stats.ts new file mode 100644 index 00000000..e64f31bc --- /dev/null +++ b/src/core/docker/store-container-stats.ts @@ -0,0 +1,96 @@ +import { getDockerClient } from "~/core/docker/client"; +import { dbFunctions } from "~/core/database/repository"; +import Docker from "dockerode"; +import { + calculateCpuPercent, + calculateMemoryUsage, +} from "~/core/utils/calculations"; + +async function storeContainerData() { + try { + const hosts = dbFunctions.getDockerHosts(); + + // Process each host concurrently and wait for them all to finish + await Promise.all( + hosts.map(async (host) => { + const docker = getDockerClient(host); + + // Test the connection with a ping + try { + await docker.ping(); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to ping docker host "${host.name}": ${errMsg}`, + ); + } + + let containers; + try { + containers = await docker.listContainers({ all: true }); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to list containers on host "${host.name}": ${errMsg}`, + ); + } + + // Process each container concurrently + await Promise.all( + containers.map(async (containerInfo) => { + const containerName = containerInfo.Names[0].replace(/^\//, ""); + try { + const container = docker.getContainer(containerInfo.Id); + + const stats: Docker.ContainerStats = await new Promise( + (resolve, reject) => { + container.stats({ stream: false }, (error, stats) => { + if (error) { + const errMsg = + error instanceof Error ? error.message : String(error); + return reject( + new Error( + `Failed to get stats for container "${containerName}" (ID: ${containerInfo.Id}) on host "${host.name}": ${errMsg}`, + ), + ); + } + if (!stats) { + return reject( + new Error( + `No stats returned for container "${containerName}" (ID: ${containerInfo.Id}) on host "${host.name}".`, + ), + ); + } + resolve(stats); + }); + }, + ); + + dbFunctions.addContainerStats( + containerInfo.Id, + host.name, + containerName, + containerInfo.Image, + containerInfo.Status, + containerInfo.State, + calculateCpuPercent(stats), + calculateMemoryUsage(stats), + ); + } catch (error) { + const errMsg = + error instanceof Error ? error.message : String(error); + throw new Error( + `Error processing container "${containerName}" (ID: ${containerInfo.Id}) on host "${host.name}": ${errMsg}`, + ); + } + }), + ); + }), + ); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to store container data: ${errMsg}`); + } +} + +export default storeContainerData; diff --git a/src/core/docker/store-host-stats.ts b/src/core/docker/store-host-stats.ts new file mode 100644 index 00000000..f8cd3527 --- /dev/null +++ b/src/core/docker/store-host-stats.ts @@ -0,0 +1,68 @@ +import { logger } from "~/core/utils/logger"; +import { dbFunctions } from "~/core/database/repository"; +import { DockerHost, HostStats } from "~/typings/docker"; +import { getDockerClient } from "~/core/docker/client"; +import { DockerInfo } from "~/typings/dockerode"; + +async function storeHostData() { + try { + const hosts = dbFunctions.getDockerHosts() as DockerHost[]; + + await Promise.all( + hosts.map(async (host) => { + const docker = getDockerClient(host); + + try { + await docker.ping(); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to ping docker host "${host.name}": ${errMsg}`, + ); + } + + let hostStats: DockerInfo; + let stats: HostStats; + try { + hostStats = await docker.info(); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to fetch stats for host "${host.name}": ${errMsg}`, + ); + } + + try { + const stats: HostStats = { + hostId: host.name, + dockerVersion: hostStats.ServerVersion, + apiVersion: hostStats.Driver, + os: hostStats.OperatingSystem, + architecture: hostStats.Architecture, + totalMemory: hostStats.MemTotal, + totalCPU: hostStats.NCPU, + labels: hostStats.Labels, + images: hostStats.Images, + containers: hostStats.Containers, + containersPaused: hostStats.ContainersPaused, + containersRunning: hostStats.ContainersRunning, + containersStopped: hostStats.ContainersStopped, + }; + + dbFunctions.updateHostStats(stats); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to store stats for host "${host.name}": ${errMsg}`, + ); + } + }), + ); + } catch (error) { + const errMsg = error instanceof Error ? error.message : String(error); + logger.error(`storeHostData failed: ${errMsg}`); + throw new Error(`Failed to store host data: ${errMsg}`); + } +} + +export default storeHostData; diff --git a/src/core/plugins/loader.ts b/src/core/plugins/loader.ts new file mode 100644 index 00000000..db77bedd --- /dev/null +++ b/src/core/plugins/loader.ts @@ -0,0 +1,38 @@ +import { pluginManager } from "./plugin-manager"; +import path from "path"; +import fs from "fs"; +import { logger } from "../utils/logger"; +import { checkFileForChangeMe } from "../utils/change-me-checker"; + +export async function loadPlugins(pluginDir: string) { + const pluginPath = path.join(process.cwd(), pluginDir); + + logger.debug(`Loading plugins (${pluginPath})`); + if (!fs.existsSync(pluginPath)) { + return; + } + + let pluginCount = 0; + const files = fs.readdirSync(pluginPath); + + for (const file of files) { + if (!file.endsWith(".plugin.ts")) { + continue + }; + + const absolutePath = path.join(pluginPath, file); + try { + await checkFileForChangeMe(absolutePath); + const module = await import(absolutePath); + const plugin = module.default; + pluginManager.register(plugin); + pluginCount++; + } catch (error) { + logger.error( + `Error while importing plugin ${absolutePath}: ${error as string}`, + ); + } + } + + logger.info(`Registered ${pluginCount} plugin(s)`); +} diff --git a/src/core/plugins/plugin-actions.ts b/src/core/plugins/plugin-actions.ts new file mode 100644 index 00000000..0b2f9357 --- /dev/null +++ b/src/core/plugins/plugin-actions.ts @@ -0,0 +1,10 @@ +import { pluginManager } from "./plugin-manager"; + +export const pluginAction = { + containerStart(containerInfo: any) { + pluginManager.handleContainerStart(containerInfo); + }, + metricsReceived(metrics: any) { + pluginManager.handleMetrics(metrics); + }, +}; diff --git a/src/core/plugins/plugin-manager.ts b/src/core/plugins/plugin-manager.ts new file mode 100644 index 00000000..614604af --- /dev/null +++ b/src/core/plugins/plugin-manager.ts @@ -0,0 +1,98 @@ +import { EventEmitter } from "events"; +import { logger } from "../utils/logger"; +import type { Plugin } from "~/typings/plugin"; +import type { ContainerInfo, HostStats } from "~/typings/docker"; + +export class PluginManager extends EventEmitter { + private plugins: Map = new Map(); + + register(plugin: Plugin) { + try { + this.plugins.set(plugin.name, plugin); + logger.debug(`Registered plugin: ${plugin.name}`); + } catch (error) { + logger.error( + `Registering plugin ${plugin.name} failed: ${error as string}`, + ); + } + } + + unregister(name: string) { + this.plugins.delete(name); + } + + // Trigger plugin flows: + handleContainerStop(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerStop?.(containerInfo); + }); + } + + handleContainerExit(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerExit?.(containerInfo); + }); + } + + handleContainerCreate(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerCreate?.(containerInfo); + }); + } + + handleContainerDestroy(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerDestroy?.(containerInfo); + }); + } + + handleContainerPause(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerPause?.(containerInfo); + }); + } + + handleContainerUnpause(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerUnpause?.(containerInfo); + }); + } + + handleContainerRestart(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerRestart?.(containerInfo); + }); + } + + handleContainerUpdate(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerUpdate?.(containerInfo); + }); + } + + handleContainerRename(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerRename?.(containerInfo); + }); + } + + handleContainerHealthStatus(containerInfo: ContainerInfo) { + this.plugins.forEach((plugin) => { + plugin.onContainerHealthStatus?.(containerInfo); + }); + } + + handleHostUnreachable(HostStats: HostStats) { + this.plugins.forEach((plugin) => { + plugin.onHostUnreachable?.(HostStats); + }); + } + + handleHostReachableAgain(HostStats: HostStats) { + this.plugins.forEach((plugin) => { + plugin.onHostReachableAgain?.(HostStats); + }); + } +} + +export const pluginManager = new PluginManager(); diff --git a/src/core/stacks/controller.ts b/src/core/stacks/controller.ts new file mode 100644 index 00000000..2ff5edb9 --- /dev/null +++ b/src/core/stacks/controller.ts @@ -0,0 +1,134 @@ +import { dbFunctions } from "../database/repository"; +import YAML from "yaml"; +import { logger } from "../utils/logger"; +import DockerCompose from "docker-compose"; +import type { Stack, ComposeSpec } from "~/typings/docker-compose"; +import type { stacks_config } from "~/typings/database"; + +async function getStackPath(stack: Stack): Promise { + const stackName = stack.name.trim().replace(/\s+/g, "_"); + return `stacks/${stackName}`; +} + +async function createStackYAML(compose_spec: Stack): Promise { + const yaml = YAML.stringify(compose_spec.compose_spec); + const stackPath = await getStackPath(compose_spec); + await Bun.write(`${stackPath}/docker-compose.yaml`, yaml, { createPath: true }); +} + +export async function deployStack( + stack: ComposeSpec, + name: string, + version: number, + source: string, + automatic_reboot_on_error: boolean, + isCustom: boolean, + image_updates: boolean, + stack_prefix?: string +): Promise { + try { + logger.debug(`Deploying Stack: ${JSON.stringify(stack)}`) + + const serviceCount = stack.services + ? Object.keys(stack.services).length + : 0; + + const resolvedPrefix = stack_prefix ?? ""; + + const stack_config: stacks_config = { + name: name, + version: version, + source, + stack_prefix: resolvedPrefix, + automatic_reboot_on_error, + container_count: serviceCount, + custom: isCustom, + image_updates, + }; + + if (!stack.name) { + logger.debug(`${JSON.stringify(stack)}`) + throw new Error("Stack name needed") + } + + dbFunctions.addStack(stack_config); + + const stackYaml: Stack = { + name: name, + source: source, + version: version, + compose_spec: stack, + } + await createStackYAML(stackYaml); + const stackPath = await getStackPath(stackYaml); + await DockerCompose.upAll({ cwd: stackPath }); + } catch (error: any) { + throw new Error(`Error while deploying Stack: ${error.message || error}`); + } +} + +export async function stopStack(stack_name: string): Promise { + try { + const stack = { + name: stack_name + } + const stackPath = await getStackPath(stack as Stack); + await DockerCompose.downAll({ cwd: stackPath }); + } catch (error: any) { + throw new Error(`Error while stopping stack "${stack_name}": ${error.message || error}`); + } +} + +export async function startStack(stack_name: string): Promise { + try { + const stack = { + name: stack_name + } + const stackPath = await getStackPath(stack as Stack); + await DockerCompose.upAll({ cwd: stackPath }); + } catch (error: any) { + throw new Error(`Error while starting stack "${stack_name}": ${error.message || error}`); + } +} + +export async function pullStackImages(stack_name: string): Promise { + try { + const stack = { + name: stack_name + } + const stackPath = await getStackPath(stack as Stack); + await DockerCompose.pullAll({ cwd: stackPath }); + } catch (error: any) { + throw new Error(`Error while pulling images for stack "${stack_name}": ${error.message || error}`); + } +} + +export async function restartStack(stack_name: string): Promise { + try { + const stack = { + name: stack_name + } + const stackPath = await getStackPath(stack as Stack); + await DockerCompose.restartAll({ cwd: stackPath }); + } catch (error: any) { + throw new Error(`Error while restarting stack "${stack_name}": ${error.message || error}`); + } +} + +export async function getStackStatus(stack_name: string): Promise { + try { + logger.debug("Retrieving status for Stack:", stack_name); + const stackYaml = { name: stack_name }; + const stackPath = await getStackPath(stackYaml as Stack); + const rawStatus = await DockerCompose.ps({ cwd: stackPath }); + + return rawStatus.data.services.reduce((acc: any, service: any) => { + acc[(service.name)] = service.state; + return acc; + }, {}); + + } catch (error: any) { + throw new Error(`Error while retrieving status for stack "${stack_name}": ${error.message || error}`); + } +} + diff --git a/src/core/utils/calculations.ts b/src/core/utils/calculations.ts new file mode 100644 index 00000000..3ead3a6d --- /dev/null +++ b/src/core/utils/calculations.ts @@ -0,0 +1,16 @@ +import type Docker from "dockerode"; + +const calculateCpuPercent = (stats: Docker.ContainerStats): number => { + const cpuDelta = + stats.cpu_stats.cpu_usage.total_usage - + stats.precpu_stats.cpu_usage.total_usage; + const systemDelta = + stats.cpu_stats.system_cpu_usage - stats.precpu_stats.system_cpu_usage; + return (cpuDelta / systemDelta) * 100; +}; + +const calculateMemoryUsage = (stats: Docker.ContainerStats): number => { + return (stats.memory_stats.usage / stats.memory_stats.limit) * 100; +}; + +export { calculateCpuPercent, calculateMemoryUsage }; diff --git a/src/core/utils/change-me-checker.ts b/src/core/utils/change-me-checker.ts new file mode 100644 index 00000000..fa19520b --- /dev/null +++ b/src/core/utils/change-me-checker.ts @@ -0,0 +1,16 @@ +import { readFile } from "fs/promises"; +import { logger } from "~/core/utils/logger"; + +export async function checkFileForChangeMe(filePath: string) { + const regex = /change[\W_]*me/i; + let content = ""; + try { + content = await readFile(filePath, "utf-8"); + } catch (error) { + logger.error("Error reading file:", error); + } + + if (regex.test(content)) { + throw new Error(`Error: The file contains 'CHANGE_ME'. Please update it.`); + } +} diff --git a/src/core/utils/logger.ts b/src/core/utils/logger.ts new file mode 100644 index 00000000..b35aeeae --- /dev/null +++ b/src/core/utils/logger.ts @@ -0,0 +1,113 @@ +import { createLogger, format, transports } from "winston"; +import path from "path"; +import chalk, { ChalkInstance } from "chalk"; +import { dbFunctions } from "../database/repository"; +import wrapAnsi from "wrap-ansi"; + +// Change to false here if dont want the spacing on a wrapped line +const padNewlines: boolean = true; + +const fileLineFormat = format((info) => { + try { + const stack = new Error().stack?.split("\n"); + if (stack) { + for (let i = 2; i < stack.length; i++) { + const line = stack[i].trim(); + // Exclude lines from node_modules or the current file + if (!line.includes("node_modules") && !line.includes(path.basename(__filename))) { + const matches = line.match(/\(?(.+):(\d+):(\d+)\)?$/); + if (matches) { + info.file = path.basename(matches[1]); + info.line = parseInt(matches[2], 10); + break; + } + } + } + } + } catch (err) { + // Ignore errors during stack trace extraction + } + return info; +}); + +const formatTerminalMessage = (message: string, prefixLength: number) => { + const maxWidth = process.stdout.columns || 80; + const wrapWidth = maxWidth - prefixLength - 15; + + if (padNewlines) { + const wrapped = wrapAnsi(chalk.gray(message), wrapWidth, { + trim: true, + hard: true, + }); + + return wrapped + .split("\n") + .map((line, i) => (i === 0 ? line : " ".repeat(prefixLength) + line)) + .join("\n"); + } + return message; +}; + +export const logger = createLogger({ + level: process.env.LOG_LEVEL || 'debug', + format: format.combine( + format.timestamp({ format: "DD/MM HH:mm:ss" }), + fileLineFormat(), + format.printf(({ timestamp, level, message, file, line }) => { + + const levelColors: Record = { + error: chalk.red.bold, + warn: chalk.yellow.bold, + info: chalk.green.bold, + debug: chalk.blue.bold, + verbose: chalk.cyan.bold, + silly: chalk.magenta.bold, + task: chalk.cyan.bold + }; + + if ((message as string).startsWith("__task__")) { + message = (message as string).replaceAll("__task__", "").trimStart(); + level = "task" + if ((message as string).startsWith("__db__")) { + message = (message as string).replaceAll("__db__", "").trimStart(); + message = `${chalk.magenta("DB")} ${message}` + } + } + + const paddedLevel = level.toUpperCase().padEnd(5); + const coloredLevel = (levelColors[level] || chalk.white)(paddedLevel); + const coloredContext = chalk.cyan(`${file as string}:${line as number}`); + const coloredTimestamp = chalk.yellow(timestamp); + + if (process.env.NODE_ENV !== "dev") { + return `${coloredLevel} [ ${coloredTimestamp} ] - ${chalk.gray( + message + )} - [ ${coloredContext} ]`; + } + + const prefix = `${paddedLevel} [ ${timestamp} ] - `; + const prefixLength = prefix.length; + const formattedMessage = formatTerminalMessage( + message as string, + prefixLength + ); + const ansiRegex = /\x1B\[[0-?9;]*[mG]/g; + + try { + dbFunctions.addLogEntry( + (level as string).replace(ansiRegex, ''), + (message as string).replace(ansiRegex, ''), + (file as string).replace(ansiRegex, ''), + line as number + ); + } catch (error) { + // Use console.error to avoid recursive logging + console.error(`Error inserting log into DB: ${String(error)}`); + process.abort() + } + + return `${coloredLevel} [ ${coloredTimestamp} ] - ${formattedMessage} - [ ${coloredContext} ]`; + }) + ), + transports: [new transports.Console()], +}); diff --git a/src/core/utils/package-json.ts b/src/core/utils/package-json.ts new file mode 100644 index 00000000..3872d561 --- /dev/null +++ b/src/core/utils/package-json.ts @@ -0,0 +1,18 @@ +import packageJson from "~/../package.json"; +const { version, description, license, contributors, dependencies, devDependencies } = packageJson; + +const authorName = packageJson.author.name; +const authorEmail = packageJson.author.email; +const authorWebsite = packageJson.author.url; + +export { + version, + description, + authorName, + authorEmail, + authorWebsite, + license, + contributors, + dependencies, + devDependencies, +}; diff --git a/src/core/utils/respone-handler.ts b/src/core/utils/respone-handler.ts new file mode 100644 index 00000000..93e0cdbe --- /dev/null +++ b/src/core/utils/respone-handler.ts @@ -0,0 +1,46 @@ +import { logger } from "~/core/utils/logger"; +import type { HTTPHeaders } from "elysia/dist/types"; +import type { ElysiaCookie } from "elysia/dist/cookies"; +import type { StatusMap } from "elysia"; + +interface set { + headers: HTTPHeaders; + status?: number | keyof StatusMap; + redirect?: string; + cookie?: Record; +} + +export const responseHandler = { + error( + set: set, + error: string, + response_message: string, + error_code?: number, + ) { + set.status = error_code || 500; + logger.error(`${response_message} - ${error}`); + return { error: `${response_message}` }; + }, + + ok(set: set, response_message: string) { + set.status = 200; + logger.debug(response_message); + return { success: true }; + }, + + simple_error(set: set, response_massage: string, status_code?: number) { + set.status = status_code || 502; + logger.warn(response_massage); + return { error: response_massage }; + }, + + reject(set: set, reject: any, response_message: string, error?: string) { + set.status = 501; + if (error) { + logger.error(`${response_message} - ${error}`); + } else { + logger.error(response_message); + } + return reject(new Error(response_message)); + }, +}; diff --git a/src/data/frontendConfiguration.json b/src/data/frontendConfiguration.json deleted file mode 100644 index 0637a088..00000000 --- a/src/data/frontendConfiguration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/data/template.json b/src/data/template.json deleted file mode 100644 index 75e12f22..00000000 --- a/src/data/template.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "text": "{{name}} is {{state}} on {{hostName}}" -} diff --git a/src/data/usePassword.txt b/src/data/usePassword.txt deleted file mode 100644 index 02e4a84d..00000000 --- a/src/data/usePassword.txt +++ /dev/null @@ -1 +0,0 @@ -false \ No newline at end of file diff --git a/src/handlers/api.ts b/src/handlers/api.ts deleted file mode 100644 index fa7f1f7e..00000000 --- a/src/handlers/api.ts +++ /dev/null @@ -1,142 +0,0 @@ -import extractRelevantData from "../utils/extractHostData"; -import { Request, Response } from "express"; -import { getDockerClient } from "../utils/dockerClient"; -import { fetchAllContainers } from "../utils/containerService"; -import { getCurrentSchedule } from "../controllers/scheduler"; -import fs from "fs"; -import checkReachability from "../utils/connectionChecker"; -const configPath = "./src/data/dockerConfig.json"; -const userConf = "./src/data/user.conf"; -import { dockerConfig } from "../typings/dockerConfig"; -import { createResponseHandler } from "./response"; - -class ApiHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - hosts() { - const ResponseHandler = createResponseHandler(this.res); - try { - const rawData = fs.readFileSync(configPath, "utf-8"); - const config: dockerConfig = JSON.parse(rawData); - - if (!config.hosts) { - return ResponseHandler.error("No hosts defined in configuration.", 400); - } - - const hosts = config.hosts.map((host) => host.name); - return ResponseHandler.rawData(hosts, "Fetched data for all hosts"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - system() { - const ResponseHandler = createResponseHandler(this.res); - try { - const rawData = fs.readFileSync(userConf, "utf8"); - const config = JSON.parse(rawData); - - if (!config) { - return ResponseHandler.error("Received empty configuration", 400); - } - - return ResponseHandler.rawData(config, "Fetched system configuration"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async hostStats(hostName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - const docker = getDockerClient(hostName); - const info = await docker.info(); - const version = await docker.version(); - const relevantData = extractRelevantData({ hostName, info, version }); - - if (!relevantData) { - ResponseHandler.error("No host found", 404); - } - - return ResponseHandler.rawData(relevantData, "Fetched Host stats"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async containers() { - const ResponseHandler = createResponseHandler(this.res); - try { - const allContainerData = await fetchAllContainers(); - return ResponseHandler.rawData( - allContainerData, - "Fetched all containers across all hosts", - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async config() { - const ResponseHandler = createResponseHandler(this.res); - try { - const rawData = fs.readFileSync(configPath); - const data = JSON.parse(rawData.toString()); - return ResponseHandler.rawData(data, "Fetched config"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - currentSchedule() { - const ResponseHandler = createResponseHandler(this.res); - try { - const currentSchedule = getCurrentSchedule(); - return ResponseHandler.rawData( - currentSchedule, - "Fetched current schedule", - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async status() { - const ResponseHandler = createResponseHandler(this.res); - try { - const data = await checkReachability(); - return ResponseHandler.rawData(data, "Fetched Status"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - frontendConfig() { - const configPath: string = "./src/data/frontendConfiguration.json"; - const ResponseHandler = createResponseHandler(this.res); - try { - const rawData = fs.readFileSync(configPath); - const data = JSON.parse(rawData.toString()); - return ResponseHandler.rawData(data, "Fetched frontend configuration"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createApiHandler = (req: Request, res: Response) => - new ApiHandler(req, res); diff --git a/src/handlers/auth.ts b/src/handlers/auth.ts deleted file mode 100644 index 4dfbd3fb..00000000 --- a/src/handlers/auth.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Request, Response } from "express"; -import { - authEnabled, - readPasswordFile, - writePasswordFile, - setFalse, -} from "../controllers/auth"; -import { createResponseHandler } from "./response"; -import bcrypt from "bcrypt"; - -const saltRounds: number = 10; - -class AuthenticationHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - async enable(password: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - if (await authEnabled()) { - return ResponseHandler.denied( - "Password Authentication is already enabled, please deactivate it first", - ); - } - - if (!password) { - return ResponseHandler.denied("Password is required"); - } - - const salt = await bcrypt.genSalt(saltRounds); - const hash = await bcrypt.hash(password, salt); - - const passwordData = { hash, salt }; - writePasswordFile(JSON.stringify(passwordData)); - - return ResponseHandler.ok("Authentication enabled successfully"); - } catch (error) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async disable(password: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - if (!password) { - return ResponseHandler.denied("Password is required"); - } - - const storedData = JSON.parse(await readPasswordFile()); - const isPasswordValid = await bcrypt.compare(password, storedData.hash); - - if (!isPasswordValid) { - return ResponseHandler.error("Invalid password", 401); - } - - await setFalse(); - return ResponseHandler.ok("Authentication disabled successfully"); - } catch (error) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createAuthenticationHandler = (req: Request, res: Response) => - new AuthenticationHandler(req, res); diff --git a/src/handlers/conf.ts b/src/handlers/conf.ts deleted file mode 100644 index b49dd2a5..00000000 --- a/src/handlers/conf.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { setFetchInterval, parseInterval } from "../controllers/scheduler"; -import { Request, Response } from "express"; -import fs from "fs"; -import { createResponseHandler } from "./response"; -import { target, dockerConfig } from "../typings/dockerConfig"; -const configPath: string = "./src/data/dockerConfig.json"; - -class ConfHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - addHost(req: Request) { - const ResponseHandler = createResponseHandler(this.res); - - try { - const { name, url, port } = req.query as unknown as target; - if (!name || !url || !port) { - return ResponseHandler.error("Name, Port, and URL are required.", 400); - } - - const config: dockerConfig = JSON.parse( - fs.readFileSync(configPath, "utf-8"), - ); - - if (config.hosts.some((host) => host.name === name)) { - return ResponseHandler.error("Host already exists.", 422); - } - - config.hosts.push({ name, url, port }); - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); - - return ResponseHandler.ok("Host added successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - removeHost(req: Request) { - const ResponseHandler = createResponseHandler(this.res); - try { - const hostName = req.query.hostName as string; - - if (!hostName) { - return ResponseHandler.error("Host name is required.", 401); - } - - const currentState = fs.readFileSync(configPath, "utf-8"); - const config: dockerConfig = JSON.parse(currentState); - - const hostIndex = config.hosts.findIndex( - (host) => host.name === hostName, - ); - - if (hostIndex === -1) { - return ResponseHandler.error("Host not found.", 404); - } - - config.hosts.splice(hostIndex, 1); - - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); - - return ResponseHandler.ok("Host removed successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - scheduler(req: Request) { - const ResponseHandler = createResponseHandler(this.res); - try { - const interval = req.query.interval as string; - const newInterval = parseInterval(interval); - - if (newInterval < 5 * 60 * 1000 || newInterval > 6 * 60 * 60 * 1000) { - return ResponseHandler.error( - "Interval must be between 5 minutes and 6 hours.", - 401, - ); - } - - setFetchInterval(newInterval); - return ResponseHandler.ok("Updated interval"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createConfHandler = (req: Request, res: Response) => - new ConfHandler(req, res); diff --git a/src/handlers/data.ts b/src/handlers/data.ts deleted file mode 100644 index 5d3bf41c..00000000 --- a/src/handlers/data.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Response, Request } from "express"; -import db from "../config/db"; -import { Table, DataRow } from "../typings/table"; -import { createResponseHandler } from "./response"; -import logger from "../utils/logger"; - -function formatRows(rows: DataRow[]): Record { - return rows.reduce( - ( - acc: Record, - row, - index: number, - ): Record => { - acc[index] = JSON.parse(row.info); - return acc; - }, - {}, - ); -} - -class DatabaseHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - latest() { - const ResponseHandler = createResponseHandler(this.res); - db.get( - "SELECT info FROM data ORDER BY timestamp DESC LIMIT 1", - (error: unknown, row: Partial> | undefined) => { - if (error) { - return ResponseHandler.critical(error as string); - } - - if (!row || !row.info) { - return ResponseHandler.error( - "No data available for /data/latest", - 404, - ); - } - - try { - return ResponseHandler.rawData( - JSON.parse(row.info), - "Read latest data", - ); - } catch (error: unknown) { - const errorMsg = - error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - }, - ); - } - - latestRaw(): Promise { - return new Promise((resolve, reject) => { - logger.debug("Reading DB"); - db.get( - "SELECT info FROM data ORDER BY timestamp DESC LIMIT 1", - (error: unknown, row: Partial> | undefined) => { - if (error) { - return reject(`Database query error: ${error}`); - } - - if (!row || !row.info) { - return reject("No data available for /data/latest"); - } - - try { - logger.info("Read latest data"); - const parsedData = JSON.parse(row.info); - logger.debug("Parsed data:", parsedData); - resolve(parsedData); - } catch (error: unknown) { - const errorMsg = - error instanceof Error ? error.message : String(error); - reject(`Error parsing data: ${errorMsg}`); - } - }, - ); - }); - } - - all() { - const ResponseHandler = createResponseHandler(this.res); - const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); - - db.all( - "SELECT info FROM data WHERE timestamp >= ?", - [oneDayAgo], - (error: unknown, rows: Pick[] | undefined) => { - if (error) { - return ResponseHandler.critical(error as string); - } - - if (!rows || rows.length === 0) { - return ResponseHandler.error("No data available", 404); - } - - return ResponseHandler.rawData(formatRows(rows), "Read database"); - }, - ); - } - - clear() { - const ResponseHandler = createResponseHandler(this.res); - db.run("DELETE FROM data", (error: unknown) => { - if (error) { - return ResponseHandler.critical(error as string); - } - - return ResponseHandler.ok("Database cleared successfully"); - }); - } -} - -export const createDatabaseHandler = (req: Request, res: Response) => - new DatabaseHandler(req, res); diff --git a/src/handlers/frontend.ts b/src/handlers/frontend.ts deleted file mode 100644 index 6b2edc55..00000000 --- a/src/handlers/frontend.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Request, Response } from "express"; -import { createResponseHandler } from "./response"; -import { - hideContainer, - unhideContainer, - addTagToContainer, - removeTagFromContainer, - pinContainer, - unpinContainer, - setLink, - removeLink, - setIcon, - removeIcon, -} from "../controllers/frontendConfiguration"; - -class FrontendHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - async show(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await unhideContainer(containerName); - return ResponseHandler.ok("Container unhidden successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async hide(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await hideContainer(containerName); - return ResponseHandler.ok("Hid container succesfully"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async addTag(containerName: string, tag: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await addTagToContainer(containerName, tag); - return ResponseHandler.ok("Tag added successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async removeTag(containerName: string, tag: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await removeTagFromContainer(containerName, tag); - ResponseHandler.ok("Tag removed successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async pin(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await pinContainer(containerName); - return ResponseHandler.ok("Container pinned successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async unPin(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await unpinContainer(containerName); - return ResponseHandler.ok("Container unpinned successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async addLink(containerName: string, link: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await setLink(containerName, link); - return ResponseHandler.ok("Link added successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async removeLink(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await removeLink(containerName); - return ResponseHandler.ok("Removed link succesfully"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async addIcon(containerName: string, icon: string, useCustomIcon: string) { - const ResponseHandler = createResponseHandler(this.res); - const iconBool = useCustomIcon === "true"; - try { - await setIcon(containerName, icon, iconBool); - return ResponseHandler.ok("Icon added successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async removeIcon(containerName: string) { - const ResponseHandler = createResponseHandler(this.res); - try { - await removeIcon(containerName); - return ResponseHandler.ok("Icon removed successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createFrontendHandler = (req: Request, res: Response) => - new FrontendHandler(req, res); diff --git a/src/handlers/graph.ts b/src/handlers/graph.ts deleted file mode 100644 index 12e05724..00000000 --- a/src/handlers/graph.ts +++ /dev/null @@ -1,82 +0,0 @@ -import cytoscape from "cytoscape"; -import logger from "../utils/logger"; -import { AllContainerData, ContainerData } from "./../typings/dockerConfig"; -import { atomicWrite } from "../utils/atomicWrite"; - -const CACHE_DIR_JSON = "./src/data/graph.json"; - -async function generateGraphJSON( - allContainerData: AllContainerData, -): Promise { - try { - logger.info("generateGraphJSON >>> Starting generation"); - - const graphData = { - nodes: [] as cytoscape.ElementDefinition[], - edges: [] as cytoscape.ElementDefinition[], - }; - - for (const [hostName, containers] of Object.entries(allContainerData)) { - if ("error" in containers) { - graphData.nodes.push({ - data: { - id: hostName, - label: `Host: ${hostName} Error: ${containers.error}`, - type: "server", - error: true, - }, - }); - } else { - const containerList = containers as ContainerData[]; - - // Host node with container count and metadata - graphData.nodes.push({ - data: { - id: hostName, - label: `${hostName}\n${containerList.length} Containers`, - type: "server", - hostName, - containerCount: containerList.length, - }, - }); - - for (const container of containerList) { - const { id, ...otherContainerProps } = container; - - graphData.nodes.push({ - data: { - id: id, - label: `${container.name}\n${container.state.toUpperCase()}`, - type: "container", - ...otherContainerProps, - }, - }); - - // Edge between host and container - graphData.edges.push({ - data: { - id: `${hostName}-${container.id}`, - source: hostName, - target: container.id, - connectionType: "host-container", - }, - }); - } - } - } - - atomicWrite(CACHE_DIR_JSON, JSON.stringify(graphData, null, 2)); - logger.info("generateGraphJSON <<< JSON file generated successfully"); - return true; - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return false; - } -} - -function getGraphFilePath() { - return { json: CACHE_DIR_JSON }; -} - -export { generateGraphJSON, getGraphFilePath }; diff --git a/src/handlers/ha.ts b/src/handlers/ha.ts deleted file mode 100644 index 16c9ae19..00000000 --- a/src/handlers/ha.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Request, Response } from "express"; -import logger from "../utils/logger"; -import { - readConfig, - prepareFilesForSync, - ensureFileExists, -} from "../controllers/highAvailability"; -import { createResponseHandler } from "./response"; - -class HaHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - async config() { - const ResponseHandler = createResponseHandler(this.res); - try { - const data = await readConfig(); - return ResponseHandler.rawData(data, "Fetched HA-Config"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async sync(req: Request) { - const ResponseHandler = createResponseHandler(this.res); - try { - const { files } = req.body; - logger.info("Received synchronization request from master node."); - if (!files || typeof files !== "object") { - return ResponseHandler.error( - "Invalid request: 'files' object is missing or invalid.", - 400, - ); - } - - for (const [filePath, content] of Object.entries(files)) { - await ensureFileExists(filePath, content as string); - } - - return ResponseHandler.ok("Synchronization completed successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async prepare() { - const ResponseHandler = createResponseHandler(this.res); - try { - logger.info("Preparing files for synchronization."); - const fileData = await prepareFilesForSync(); - return ResponseHandler.rawData( - fileData, - "Done preparing files for synchronization", - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createHaHandler = (req: Request, res: Response) => - new HaHandler(req, res); diff --git a/src/handlers/notification.ts b/src/handlers/notification.ts deleted file mode 100644 index 9c10a599..00000000 --- a/src/handlers/notification.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Request, Response } from "express"; -import fs from "fs"; -import notify from "../utils/notifications/_notify"; -const dataTemplate = "./src/data/template.json"; -import { TemplateData } from "../typings/template"; -import { createResponseHandler } from "./response"; - -function isTemplateData(data: TemplateData): data is TemplateData { - return ( - data !== null && typeof data === "object" && typeof data.text === "string" - ); -} - -class NotificationHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - getTemplate() { - const ResponseHandler = createResponseHandler(this.res); - try { - fs.readFile(dataTemplate, "utf-8", (error: unknown, data) => { - if (error) { - return ResponseHandler.error(error as string, 400); - } - return ResponseHandler.rawData( - JSON.parse(data), - "Fetched notification template", - ); - }); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - setTemplate(req: Request) { - const ResponseHandler = createResponseHandler(this.res); - const newTemplate: TemplateData = req.body; - - try { - if (!isTemplateData(newTemplate)) { - return ResponseHandler.error( - "Invalid input format. Expected JSON with a 'text' field.", - 400, - ); - } - - fs.writeFileSync(dataTemplate, JSON.stringify(newTemplate, null, 2)); - return ResponseHandler.ok("Template updated successfully."); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async test(req: Request) { - const { type, containerId } = req.params; - const ResponseHandler = createResponseHandler(this.res); - - try { - await notify(type, containerId); - return ResponseHandler.ok("Sent test notification"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } -} - -export const createNotificationHandler = (req: Request, res: Response) => - new NotificationHandler(req, res); diff --git a/src/handlers/response.ts b/src/handlers/response.ts deleted file mode 100644 index ee062102..00000000 --- a/src/handlers/response.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Response } from "express"; -import logger from "../utils/logger"; - -class ResponseHandler { - private res: Response; - - constructor(res: Response) { - this.res = res; - } - - rawData(data: unknown, message: string) { - logger.info(message); - this.res.status(200).json(data); - } - - ok(message: string) { - logger.info(message); - this.res.status(200).json({ status: "success", message }); - } - - denied(message: string) { - logger.warn(message); - this.res.status(403).json({ status: "denied", message }); - } - - error(message: string, code: number) { - logger.error(`Code: ${code} - ${message}`); - this.res.status(code).json({ status: "error", message }); - } - - critical(log: string) { - logger.error(log.replace(/\n|\r/g, "")); - this.res.status(500).json({ - status: "critical", - message: "Please see the server logs for more info", - }); - } -} - -export const createResponseHandler = (res: Response) => - new ResponseHandler(res); diff --git a/src/handlers/stack.ts b/src/handlers/stack.ts deleted file mode 100644 index 0f15e166..00000000 --- a/src/handlers/stack.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { Response, Request } from "express"; -import { - createStack, - getStackConfig, - getStackCompose, - writeEnvFile, - getEnvFile, -} from "../config/stacks"; -import { DockerComposeFile } from "../typings/dockerCompose"; -import logger from "../utils/logger"; -import * as compose from "docker-compose"; -import { createResponseHandler } from "./response"; -import { stackConfig } from "../typings/stackConfig"; -import { dockerStackEnv } from "../typings/dockerStackEnv"; -import path from "path"; - -const PROJECT_ROOT = path.resolve(__dirname, "../.."); - -export async function validate(name: string): Promise { - const config: stackConfig = JSON.parse(await getStackConfig()); - if (!config.stacks.find((element) => element === name)) { - throw new Error("Stack not found"); - } - - return true; -} - -async function composeAction(option: string, name: string): Promise { - const composeFile: string = path.join(PROJECT_ROOT, `stacks/${name}`); - try { - switch (option) { - case "start": { - await compose.upAll({ cwd: composeFile, log: false }); - break; - } - case "stop": { - await compose.downAll({ cwd: composeFile, log: false }); - break; - } - default: - throw new Error(`Invalid option: ${option}`); - } - } catch (err) { - let errorMessage: string; - const portAllocated: string = "port is already allocated"; - - if (err instanceof Error) { - errorMessage = err.message; - } else if (typeof err === "object" && err !== null) { - errorMessage = JSON.stringify(err); - } else { - errorMessage = String(err); - } - - if (errorMessage.search(portAllocated)) { - logger.error("Port(s) already allocated"); - } - throw new Error(errorMessage); - } -} - -class StackHandler { - private req: Request; - private res: Response; - - constructor(req: Request, res: Response) { - this.req = req; - this.res = res; - } - - async createStack(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const name: string = req.params.name; - const content: DockerComposeFile = req.body; - let override = false; - override = req.query.override == "true"; - - await createStack(name, content, override); - return ResponseHandler.ok("Stack created"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async start(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const name: string = req.params.name; - await validate(name); - await composeAction("start", name); - return ResponseHandler.ok("Stack started"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async stop(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const name: string = req.params.name; - await validate(name); - await composeAction("stop", name); - return ResponseHandler.ok("Stack stopped"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } - } - - async stackCompose(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const { name } = req.params; - return ResponseHandler.rawData( - await getStackCompose(name), - "Stack compose fetched", - ); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg.replace(/\n|\r/g, "")); - throw new Error(errorMsg); - } - } - - async setStackEnv(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const data: dockerStackEnv = req.body; - const name: string = req.params.name; - if (await writeEnvFile(name, data)) { - return ResponseHandler.ok("Wrote docker.env"); - } else { - return ResponseHandler.critical( - "Something went wrong while writing the env File!", - ); - } - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg.replace(/\n|\r/g, "")); - throw new Error(errorMsg); - } - } - - async getStackEnv(req: Request, res: Response) { - const ResponseHandler = createResponseHandler(res); - try { - const name: string = req.params.name; - const data = await getEnvFile(name); - if (data == null) { - return ResponseHandler.error( - "No environment file found for this Stack!", - 404, - ); - } - return ResponseHandler.rawData(data, "Read docker.env"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg.replace(/\n|\r/g, "")); - throw new Error(errorMsg); - } - } -} - -export const createStackHandler = (req: Request, res: Response) => - new StackHandler(req, res); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..a2dfb814 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,87 @@ +import { swagger } from "@elysiajs/swagger"; +import { Elysia } from "elysia"; +import { dbFunctions } from "~/core/database/repository"; +import { loadPlugins } from "~/core/plugins/loader"; +import { logger } from "~/core/utils/logger"; +import { dockerRoutes } from "~/routes/docker-manager"; +import { dockerStatsRoutes } from "~/routes/docker-stats"; +import { backendLogs } from "~/routes/logs"; +import { dockerWebsocketRoutes } from "~/routes/docker-websocket"; +import { stackRoutes } from "./routes/stacks"; +import { apiConfigRoutes } from "~/routes/api-config"; +import { setSchedules } from "~/core/docker/scheduler"; +import staticPlugin from "@elysiajs/static"; + +console.log("") +dbFunctions.init(); + +const DockStatAPI = new Elysia() + .use(staticPlugin()) + .use( + swagger({ + documentation: { + info: { + title: "DockStatAPI", + version: "2.1.0", + description: "Docker monitoring API with plugin support", + }, + tags: [ + { + name: "Statistics", + description: + "All endpoints for fetching statistics of hosts / containers", + }, + { + name: "Management", + description: "Various endpoints for managing DockStatAPI", + }, + { + name: "Stacks", + description: "DockStat's Stack functionality", + }, + { + name: "Utils", + description: "Various utilities which might be useful", + }, + ], + }, + }), + ) + .use(dockerRoutes) + .use(dockerStatsRoutes) + .use(backendLogs) + .use(dockerWebsocketRoutes) + .use(apiConfigRoutes) + .use(stackRoutes) + .get("/health", () => ({ status: "healthy" }), { tags: ["Utils"] }) + .onError(({ code, set }) => { + if (code === 'NOT_FOUND') { + logger.warn("Unknown route, showing error page!") + set.status = 404 + set.headers['Content-Type'] = 'text/html' + return Bun.file('public/404.html') + } + }); + +async function startServer() { + try { + await loadPlugins("./src/plugins"); + DockStatAPI.listen(3000, ({ hostname, port }) => { + console.log("----- [ ############## ]") + logger.info(`DockStatAPI is running at http://${hostname}:${port}`); + logger.info( + `Swagger API Documentation available at http://${hostname}:${port}/swagger`, + ); + }); + } catch (error) { + logger.error("Failed to start server:", error); + process.exit(1); + } +} + +await setSchedules(); +await startServer(); + +logger.info("Started server"); +console.log("----- [ ############## ]") + diff --git a/src/init.ts b/src/init.ts deleted file mode 100644 index 188542f6..00000000 --- a/src/init.ts +++ /dev/null @@ -1,69 +0,0 @@ -import express, { Request, Response, NextFunction } from "express"; -import process from "node:process"; -import swaggerDocs from "./utils/swaggerDocs"; -import auth from "./routes/auth/routes"; -import data from "./routes/data/routes"; -import frontend from "./routes/frontendController/routes"; -import api from "./routes/getter/routes"; -import notificationService from "./routes/notifications/routes"; -import conf from "./routes/setter/routes"; -import graph from "./routes/graphs/routes"; -import authMiddleware from "./middleware/authMiddleware"; -import ha from "./routes/highavailability/routes"; -import trustedProxies from "./controllers/proxy"; -import { limiter } from "./middleware/rateLimiter"; -import { scheduleFetch } from "./controllers/scheduler"; -import { Server } from 'http'; -import cors from "cors"; -import { setupWebSocket } from "./utils/webSocket"; -import stacks from "./routes/stack/routes"; -import { blockWhileLocked } from "./middleware/checkLock"; -import logger from "./utils/logger"; -import initFiles from "./config/initFiles"; - -const LAB = [limiter, authMiddleware, blockWhileLocked]; - -const initializeApp = (app: express.Application, server: Server): void => { - initFiles(); - - try { - logger.debug("Starting Websocket server, with these endpoints:"); - logger.debug("ws://localhost:9876/wss/container-data") - logger.debug("ws://localhost:9876/wss/server-logs") - setupWebSocket(server); - } catch (error: unknown) { - logger.error("Error starting WebSocket: ", error) - } - - app.use(cors()); - app.use(express.json()); - - if (process.env.NODE_ENV !== "production") { - app.use("/api-docs", (req: Request, res: Response, next: NextFunction) => - next(), - ); - app.get("/", (req: Request, res: Response) => { - res.redirect("/api-docs"); - }); - swaggerDocs(app); - } - - trustedProxies(app); - scheduleFetch(); - - app.use("/api", LAB, api); - app.use("/conf", LAB, conf); - app.use("/auth", LAB, auth); - app.use("/data", LAB, data); - app.use("/frontend", LAB, frontend); - app.use("/graph", LAB, graph); - app.use("/notification-service", LAB, notificationService); - app.use("/stacks", LAB, stacks); - app.use("/ha", limiter, authMiddleware, ha); - - process.on("exit", (code: number) => { - logger.warn(`Server exiting (Code: ${code})`); - }); -}; - -export default initializeApp; diff --git a/src/middleware/authMiddleware.ts b/src/middleware/authMiddleware.ts deleted file mode 100644 index 414b2762..00000000 --- a/src/middleware/authMiddleware.ts +++ /dev/null @@ -1,51 +0,0 @@ -import bcrypt from "bcrypt"; -import { Request, Response, NextFunction } from "express"; -import logger from "../utils/logger"; -import { rateLimitedReadFile } from "../utils/rateLimitFS"; -import { createResponseHandler } from "../handlers/response"; -const passwordFile = "./src/data/password.json"; -const passwordBool = "./src/data/usePassword.txt"; - -async function authMiddleware( - req: Request, - res: Response, - next: NextFunction, -): Promise { - const ResponseHandler = createResponseHandler(res); - try { - const authStatusData = await rateLimitedReadFile(passwordBool); - const isAuthEnabled = authStatusData.trim() === "true"; - - if (!isAuthEnabled) { - logger.warn("You are not using authentication, please enable it."); - logger.debug("Authentication disabled, skipping login process..."); - return next(); - } - - const providedPassword = req.headers["x-password"]; - if (!providedPassword) { - ResponseHandler.denied("Password required"); - return; - } - - const passwordData = await rateLimitedReadFile(passwordFile); - const storedData = JSON.parse(passwordData); - - const passwordMatch = await bcrypt.compare( - providedPassword as string, - storedData.hash, - ); - if (!passwordMatch) { - ResponseHandler.error("Invalid Password", 402); - return; - } - - logger.debug("Authentication succesfull"); - next(); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } -} - -export default authMiddleware; diff --git a/src/middleware/checkLock.ts b/src/middleware/checkLock.ts deleted file mode 100644 index c01540fe..00000000 --- a/src/middleware/checkLock.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Request, Response, NextFunction } from "express"; -import { rateLimitedExistsSync } from "../utils/rateLimitFS"; -import { createResponseHandler } from "../handlers/response"; - -const lockFilePath = "./src/data/ha.lock"; - -export async function blockWhileLocked( - req: Request, - res: Response, - next: NextFunction, -): Promise { - const ResponseHandler = createResponseHandler(res); - if (await rateLimitedExistsSync(lockFilePath)) { - ResponseHandler.error( - "Service unavailable. The high-availability lock is currently active. Please try again later.", - 503, - ); - } else { - next(); - } -} diff --git a/src/middleware/rateLimiter.ts b/src/middleware/rateLimiter.ts deleted file mode 100644 index dc64af25..00000000 --- a/src/middleware/rateLimiter.ts +++ /dev/null @@ -1,8 +0,0 @@ -import rateLimit from "express-rate-limit"; - -export const limiter = rateLimit({ - windowMs: 5 * 60 * 1000, // 5 minutes - limit: 300, // Limit each IP to 300 requests per `window` (here, per 5 minutes) - standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers - legacyHeaders: false, // Disable the `X-RateLimit-*` headers -}); diff --git a/src/misc/.tmux.sh b/src/misc/.tmux.sh deleted file mode 100644 index a929a1a3..00000000 --- a/src/misc/.tmux.sh +++ /dev/null @@ -1 +0,0 @@ -[ -z "$TMUX" ] && tmux new-session -d -s docker 'docker compose -f docker/docker-compose.yaml logs -f master' \; rename-window 'master' \; new-window 'docker compose -f docker/docker-compose.yaml logs -f slave' \; rename-window 'slave' \; new-window 'docker compose -f docker/docker-compose.yaml logs -f test-socket-proxy' \; rename-window 'proxy' \; attach-session || echo 'Already inside a tmux session. Exiting.' diff --git a/src/misc/createEnvDev.sh b/src/misc/createEnvDev.sh deleted file mode 100755 index 1f231aa6..00000000 --- a/src/misc/createEnvDev.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# Version -VERSION="$(cat ./package.json | grep version | cut -d '"' -f 4)" - -# Automatic Stack environment management -AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT="${AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT:-true}" - -# Docker -if grep -q '/docker' /proc/1/cgroup 2>/dev/null || [ -f /.dockerenv ]; then - RUNNING_IN_DOCKER="true" -else - RUNNING_IN_DOCKER="false" -fi - -# Default dev log level -LOG_LEVEL="${LOG_LEVEL:-debug}" - -echo -n "\ -{ - \"VERSION\": \"${VERSION}\", - \"RUNNING_IN_DOCKER\": \"${RUNNING_IN_DOCKER}\", - \"TRUSTED_PROXIES\": \"${TRUSTED_PROXIES}\", - \"HA_MASTER\": \"${HA_MASTER}\", - \"HA_MASTER_IP\": \"${HA_MASTER_IP}\", - \"HA_NODE\": \"${HA_NODE}\", - \"HA_UNSAFE\": \"${HA_UNSAFE}\", - \"DISCORD_WEBHOOK_URL\": \"${DISCORD_WEBHOOK_URL}\", - \"EMAIL_SENDER\": \"${EMAIL_SENDER}\", - \"EMAIL_RECIPIENT\": \"${EMAIL_RECIPIENT}\", - \"EMAIL_PASSWORD\": \"${EMAIL_PASSWORD}\", - \"EMAIL_SERVICE\": \"${EMAIL_SERVICE}\", - \"PUSHBULLET_ACCESS_TOKEN\": \"${PUSHBULLET_ACCESS_TOKEN}\", - \"PUSHOVER_USER_KEY\": \"${PUSHOVER_USER_KEY}\", - \"PUSHOVER_API_TOKEN\": \"${PUSHOVER_API_TOKEN}\", - \"SLACK_WEBHOOK_URL\": \"${SLACK_WEBHOOK_URL}\", - \"TELEGRAM_BOT_TOKEN\": \"${TELEGRAM_BOT_TOKEN}\", - \"TELEGRAM_CHAT_ID\": \"${TELEGRAM_CHAT_ID}\", - \"WHATSAPP_API_URL\": \"${WHATSAPP_API_URL}\", - \"WHATSAPP_RECIPIENT\": \"${WHATSAPP_RECIPIENT}\", - \"AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT\": \"${AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT}\", - \"LOG_LEVEL\": \"${LOG_LEVEL}\" -} \ -" > ./src/data/variables.json || exit 1 diff --git a/src/misc/createEnvFile.sh b/src/misc/createEnvFile.sh deleted file mode 100755 index 0fbd15de..00000000 --- a/src/misc/createEnvFile.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# Version -VERSION="$(cat ./package.json | grep version | cut -d '"' -f 4)" - -# Automatic Stack environment management -AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT="${AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT:-true}" - -# Docker -if grep -q '/docker' /proc/1/cgroup 2>/dev/null || [ -f /.dockerenv ]; then - RUNNING_IN_DOCKER="true" -else - RUNNING_IN_DOCKER="false" -fi - -# Default log level -LOG_LEVEL="${LOG_LEVEL:-info}" - -echo -n "\ -{ - \"VERSION\": \"${VERSION}\", - \"RUNNING_IN_DOCKER\": \"${RUNNING_IN_DOCKER}\", - \"TRUSTED_PROXIES\": \"${TRUSTED_PROXIES}\", - \"HA_MASTER\": \"${HA_MASTER}\", - \"HA_MASTER_IP\": \"${HA_MASTER_IP}\", - \"HA_NODE\": \"${HA_NODE}\", - \"HA_UNSAFE\": \"${HA_UNSAFE}\", - \"DISCORD_WEBHOOK_URL\": \"${DISCORD_WEBHOOK_URL}\", - \"EMAIL_SENDER\": \"${EMAIL_SENDER}\", - \"EMAIL_RECIPIENT\": \"${EMAIL_RECIPIENT}\", - \"EMAIL_PASSWORD\": \"${EMAIL_PASSWORD}\", - \"EMAIL_SERVICE\": \"${EMAIL_SERVICE}\", - \"PUSHBULLET_ACCESS_TOKEN\": \"${PUSHBULLET_ACCESS_TOKEN}\", - \"PUSHOVER_USER_KEY\": \"${PUSHOVER_USER_KEY}\", - \"PUSHOVER_API_TOKEN\": \"${PUSHOVER_API_TOKEN}\", - \"SLACK_WEBHOOK_URL\": \"${SLACK_WEBHOOK_URL}\", - \"TELEGRAM_BOT_TOKEN\": \"${TELEGRAM_BOT_TOKEN}\", - \"TELEGRAM_CHAT_ID\": \"${TELEGRAM_CHAT_ID}\", - \"WHATSAPP_API_URL\": \"${WHATSAPP_API_URL}\", - \"WHATSAPP_RECIPIENT\": \"${WHATSAPP_RECIPIENT}\", - \"AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT\": \"${AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT}\", - \"LOG_LEVEL\": \"${LOG_LEVEL}\" -} \ -" > /api/src/data/variables.json || exit 1 diff --git a/src/misc/credits.sh b/src/misc/credits.sh deleted file mode 100755 index 3db14f64..00000000 --- a/src/misc/credits.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -if ! command -v jq 2>&1 >/dev/null -then - echo "ERROR: jq could not be found" - exit 1 -fi - - -LICENSE_JSON=$(npx license-checker \ - --exclude 'MIT, MIT-0, MIT OR X11, BSD, ISC, Unlicense, CC0-1.0, Python-2.0: 1' \ - --json) - -{ - echo -e "# CREDITS\n" - echo -e "This file shows all npm packages used in DockStatAPI (also Dev packages)\n" -} > CREDITS.md - -jq -r ' - to_entries | - group_by(.value.licenses)[] | - "### License: \(.[0].value.licenses)\n\n" + - "| Name | Repository | Publisher |\n|------|-------------|-----------|\n" + - (map( - "| \(.key) | \(.value.repository // "N/A") | \(.value.publisher // "N/A") |" - ) | join("\n")) + "\n\n" -' <<< "$LICENSE_JSON" >> CREDITS.md - -echo "Markdown file with license information has been created: CREDITS.md" diff --git a/src/misc/dependencyGraphs/.dependency-cruiser.cjs b/src/misc/dependencyGraphs/.dependency-cruiser.cjs deleted file mode 100644 index d734a682..00000000 --- a/src/misc/dependencyGraphs/.dependency-cruiser.cjs +++ /dev/null @@ -1,359 +0,0 @@ -/** @type {import('dependency-cruiser').IConfiguration} */ -module.exports = { - forbidden: [ - { - name: "no-circular", - severity: "warn", - comment: - "This dependency is part of a circular relationship. You might want to revise " + - "your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ", - from: {}, - to: { - circular: true, - }, - }, - { - name: "no-orphans", - comment: - "This is an orphan module - it's likely not used (anymore?). Either use it or " + - "remove it. If it's logical this module is an orphan (i.e. it's a config file), " + - "add an exception for it in your dependency-cruiser configuration. By default " + - "this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration " + - "files (.d.ts), tsconfig.json and some of the babel and webpack configs.", - severity: "warn", - from: { - orphan: true, - pathNot: [ - "(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$", // dot files - "[.]d[.]ts$", // TypeScript declaration files - "(^|/)tsconfig[.]json$", // TypeScript config - "(^|/)(?:babel|webpack)[.]config[.](?:js|cjs|mjs|ts|cts|mts|json)$", // other configs - ], - }, - to: {}, - }, - { - name: "no-deprecated-core", - comment: - "A module depends on a node core module that has been deprecated. Find an alternative - these are " + - "bound to exist - node doesn't deprecate lightly.", - severity: "warn", - from: {}, - to: { - dependencyTypes: ["core"], - path: [ - "^v8/tools/codemap$", - "^v8/tools/consarray$", - "^v8/tools/csvparser$", - "^v8/tools/logreader$", - "^v8/tools/profile_view$", - "^v8/tools/profile$", - "^v8/tools/SourceMap$", - "^v8/tools/splaytree$", - "^v8/tools/tickprocessor-driver$", - "^v8/tools/tickprocessor$", - "^node-inspect/lib/_inspect$", - "^node-inspect/lib/internal/inspect_client$", - "^node-inspect/lib/internal/inspect_repl$", - "^async_hooks$", - "^punycode$", - "^domain$", - "^constants$", - "^sys$", - "^_linklist$", - "^_stream_wrap$", - ], - }, - }, - { - name: "not-to-deprecated", - comment: - "This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later " + - "version of that module, or find an alternative. Deprecated modules are a security risk.", - severity: "warn", - from: {}, - to: { - dependencyTypes: ["deprecated"], - }, - }, - { - name: "no-non-package-json", - severity: "error", - comment: - "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. " + - "That's problematic as the package either (1) won't be available on live (2 - worse) will be " + - "available on live with an non-guaranteed version. Fix it by adding the package to the dependencies " + - "in your package.json.", - from: {}, - to: { - dependencyTypes: ["npm-no-pkg", "npm-unknown"], - }, - }, - { - name: "not-to-unresolvable", - comment: - "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " + - "module: add it to your package.json. In all other cases you likely already know what to do.", - severity: "error", - from: {}, - to: { - couldNotResolve: true, - }, - }, - { - name: "no-duplicate-dep-types", - comment: - "Likely this module depends on an external ('npm') package that occurs more than once " + - "in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " + - "maintenance problems later on.", - severity: "warn", - from: {}, - to: { - moreThanOneDependencyType: true, - // as it's pretty common to have a type import be a type only import - // _and_ (e.g.) a devDependency - don't consider type-only dependency - // types for this rule - dependencyTypesNot: ["type-only"], - }, - }, - - /* rules you might want to tweak for your specific situation: */ - - { - name: "not-to-spec", - comment: - "This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. " + - "If there's something in a spec that's of use to other modules, it doesn't have that single " + - "responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.", - severity: "error", - from: {}, - to: { - path: "[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", - }, - }, - { - name: "not-to-dev-dep", - severity: "error", - comment: - "This module depends on an npm package from the 'devDependencies' section of your " + - "package.json. It looks like something that ships to production, though. To prevent problems " + - "with npm packages that aren't there on production declare it (only!) in the 'dependencies'" + - "section of your package.json. If this module is development only - add it to the " + - "from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration", - from: { - path: "^(./)", - pathNot: "[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", - }, - to: { - dependencyTypes: ["npm-dev"], - // type only dependencies are not a problem as they don't end up in the - // production code or are ignored by the runtime. - dependencyTypesNot: ["type-only"], - pathNot: ["node_modules/@types/"], - }, - }, - { - name: "optional-deps-used", - severity: "info", - comment: - "This module depends on an npm package that is declared as an optional dependency " + - "in your package.json. As this makes sense in limited situations only, it's flagged here. " + - "If you're using an optional dependency here by design - add an exception to your" + - "dependency-cruiser configuration.", - from: {}, - to: { - dependencyTypes: ["npm-optional"], - }, - }, - { - name: "peer-deps-used", - comment: - "This module depends on an npm package that is declared as a peer dependency " + - "in your package.json. This makes sense if your package is e.g. a plugin, but in " + - "other cases - maybe not so much. If the use of a peer dependency is intentional " + - "add an exception to your dependency-cruiser configuration.", - severity: "warn", - from: {}, - to: { - dependencyTypes: ["npm-peer"], - }, - }, - ], - options: { - /* Which modules not to follow further when encountered */ - doNotFollow: { - /* path: an array of regular expressions in strings to match against */ - path: ["../node_modules"], - }, - - /* Which modules to exclude */ - // exclude : { - // /* path: an array of regular expressions in strings to match against */ - // path: '', - // }, - - /* Which modules to exclusively include (array of regular expressions in strings) - dependency-cruiser will skip everything not matching this pattern - */ - // includeOnly : [''], - - /* List of module systems to cruise. - When left out dependency-cruiser will fall back to the list of _all_ - module systems it knows of. It's the default because it's the safe option - It might come at a performance penalty, though. - moduleSystems: ['amd', 'cjs', 'es6', 'tsd'] - - As in practice only commonjs ('cjs') and ecmascript modules ('es6') - are widely used, you can limit the moduleSystems to those. - */ - - // moduleSystems: ['cjs', 'es6'], - - /* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/' - to open it on your online repo or `vscode://file/${process.cwd()}/` to - open it in visual studio code), - */ - // prefix: `vscode://file/${process.cwd()}/`, - - /* false (the default): ignore dependencies that only exist before typescript-to-javascript compilation - true: also detect dependencies that only exist before typescript-to-javascript compilation - "specify": for each dependency identify whether it only exists before compilation or also after - */ - // tsPreCompilationDeps: false, - - /* list of extensions to scan that aren't javascript or compile-to-javascript. - Empty by default. Only put extensions in here that you want to take into - account that are _not_ parsable. - */ - // extraExtensionsToScan: [".json", ".jpg", ".png", ".svg", ".webp"], - - /* if true combines the package.jsons found from the module up to the base - folder the cruise is initiated from. Useful for how (some) mono-repos - manage dependencies & dependency definitions. - */ - // combinedDependencies: false, - - /* if true leave symlinks untouched, otherwise use the realpath */ - // preserveSymlinks: false, - - /* TypeScript project file ('tsconfig.json') to use for - (1) compilation and - (2) resolution (e.g. with the paths property) - - The (optional) fileName attribute specifies which file to take (relative to - dependency-cruiser's current working directory). When not provided - defaults to './tsconfig.json'. - */ - //tsConfig: { - //fileName: "../tsconfig.json", - //}, - - /* Webpack configuration to use to get resolve options from. - - The (optional) fileName attribute specifies which file to take (relative - to dependency-cruiser's current working directory. When not provided defaults - to './webpack.conf.js'. - - The (optional) `env` and `arguments` attributes contain the parameters - to be passed if your webpack config is a function and takes them (see - webpack documentation for details) - */ - // webpackConfig: { - // fileName: 'webpack.config.js', - // env: {}, - // arguments: {} - // }, - - /* Babel config ('.babelrc', '.babelrc.json', '.babelrc.json5', ...) to use - for compilation - */ - // babelConfig: { - // fileName: '.babelrc', - // }, - - /* List of strings you have in use in addition to cjs/ es6 requires - & imports to declare module dependencies. Use this e.g. if you've - re-declared require, use a require-wrapper or use window.require as - a hack. - */ - // exoticRequireStrings: [], - - /* options to pass on to enhanced-resolve, the package dependency-cruiser - uses to resolve module references to disk. The values below should be - suitable for most situations - - If you use webpack: you can also set these in webpack.conf.js. The set - there will override the ones specified here. - */ - enhancedResolveOptions: { - /* What to consider as an 'exports' field in package.jsons */ - exportsFields: ["exports"], - /* List of conditions to check for in the exports field. - Only works when the 'exportsFields' array is non-empty. - */ - conditionNames: ["import", "require", "node", "default", "types"], - /* - The extensions, by default are the same as the ones dependency-cruiser - can access (run `npx depcruise --info` to see which ones that are in - _your_ environment). If that list is larger than you need you can pass - the extensions you actually use (e.g. ["", ".jsx"]). This can speed - up module resolution, which is the most expensive step. - */ - extensions: ["", ".jsx", ".ts", ".tsx"], - /* What to consider a 'main' field in package.json */ - mainFields: ["module", "main", "types", "typings"], - /* - A list of alias fields in package.jsons - See [this specification](https://github.com/defunctzombie/package-browser-field-spec) and - the webpack [resolve.alias](https://webpack.js.org/configuration/resolve/#resolvealiasfields) - documentation - - Defaults to an empty array (= don't use alias fields). - */ - // aliasFields: ["browser"], - }, - reporterOptions: { - dot: { - /* pattern of modules that can be consolidated in the detailed - graphical dependency graph. The default pattern in this configuration - collapses everything in node_modules to one folder deep so you see - the external modules, but their innards. - */ - collapsePattern: "node_modules/(?:@[^/]+/[^/]+|[^/]+)", - - /* Options to tweak the appearance of your graph.See - https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#reporteroptions - for details and some examples. If you don't specify a theme - dependency-cruiser falls back to a built-in one. - */ - theme: { - graph: { - /* splines: "ortho" gives straight lines, but is slow on big graphs - splines: "true" gives bezier curves (fast, not as nice as ortho) - */ - ortho: "true", - }, - }, - }, - archi: { - /* pattern of modules that can be consolidated in the high level - graphical dependency graph. If you use the high level graphical - dependency graph reporter (`archi`) you probably want to tweak - this collapsePattern to your situation. - */ - collapsePattern: - "^(?:packages|src|lib(s?)|app(s?)|bin|test(s?)|spec(s?))/[^/]+|node_modules/(?:@[^/]+/[^/]+|[^/]+)", - - /* Options to tweak the appearance of your graph. If you don't specify a - theme for 'archi' dependency-cruiser will use the one specified in the - dot section above and otherwise use the default one. - */ - // theme: { }, - }, - text: { - highlightFocused: true, - }, - }, - }, -}; -// generated: dependency-cruiser@16.5.0 on 2024-11-08T20:57:37.261Z diff --git a/src/misc/dependencyGraphs/createDependencyGraph.sh b/src/misc/dependencyGraphs/createDependencyGraph.sh deleted file mode 100755 index 5fe007aa..00000000 --- a/src/misc/dependencyGraphs/createDependencyGraph.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -TMP=$(mktemp) -IGNORE="node_modules|logger|.dependency-cruiser|path|fs|os|https|net|process|util" - -cat ./src/init.ts | grep "./routes" | awk '{print $2,$4}' > $TMP - -spawn_worker(){ - local line="$1" - local target_route="$(echo "$line" | cut -d '"' -f2 | sed 's|^./routes|./src/routes|').ts" - local route=$(echo "$line" | awk '{print $1}') - - echo -e "\nRoute: $route \n${target_route}" - - test=true depcruise \ - -c ./src/misc/dependencyGraphs/.dependency-cruiser.cjs \ - -p cli-feedback \ - -T mermaid \ - -x "$IGNORE" \ - -f ./src/misc/dependencyGraphs/mermaid-${route}.txt \ - ${target_route} || exit 1 -} - -while read line; do - spawn_worker "$line" & -done < <(cat $TMP) - -npx depcruise \ - -c ./src/misc/dependencyGraphs/.dependency-cruiser.cjs \ - -p cli-feedback \ - -T mermaid \ - -x "$IGNORE" \ - -f ./src/misc/dependencyGraphs/mermaid-all.txt \ - ./src/server.ts || exit 1 - -wait - -find ./src/misc/dependencyGraphs -type f -name "*.txt" -exec sed -i 's/flowchart LR/flowchart TB/g' {} + - -echo -e "\n========\n\n DONE\n\n========" - -exit 0 diff --git a/src/misc/dependencyGraphs/mermaid-all.txt b/src/misc/dependencyGraphs/mermaid-all.txt deleted file mode 100644 index 1cb2ebe8..00000000 --- a/src/misc/dependencyGraphs/mermaid-all.txt +++ /dev/null @@ -1,113 +0,0 @@ -flowchart TB - -subgraph 0["src"] -1["server.ts"] -2["init.ts"] -subgraph 3["config"] -4["initFiles.ts"] -7["variables.ts"] -B["db.ts"] -end -subgraph 5["controllers"] -6["proxy.ts"] -A["scheduler.ts"] -C["fetchData.ts"] -N["auth.ts"] -U["frontendConfiguration.ts"] -14["highAvailability.ts"] -end -subgraph 8["data"] -9["variables.json"] -end -subgraph D["middleware"] -E["authMiddleware.ts"] -H["checkLock.ts"] -I["rateLimiter.ts"] -end -subgraph F["handlers"] -G["response.ts"] -M["auth.ts"] -Q["data.ts"] -T["frontend.ts"] -X["api.ts"] -10["graph.ts"] -13["ha.ts"] -19["notification.ts"] -1C["conf.ts"] -end -subgraph J["routes"] -subgraph K["auth"] -L["routes.ts"] -end -subgraph O["data"] -P["routes.ts"] -end -subgraph R["frontendController"] -S["routes.ts"] -end -subgraph V["getter"] -W["routes.ts"] -end -subgraph Y["graphs"] -Z["routes.ts"] -end -subgraph 11["highavailability"] -12["routes.ts"] -end -subgraph 17["notifications"] -18["routes.ts"] -end -subgraph 1A["setter"] -1B["routes.ts"] -end -end -subgraph 15["typings"] -16["ha.ts"] -end -end -1-->2 -2-->4 -2-->6 -2-->A -2-->E -2-->H -2-->I -2-->L -2-->P -2-->S -2-->W -2-->Z -2-->12 -2-->18 -2-->1B -6-->7 -7-->9 -A-->B -A-->C -C-->B -E-->G -H-->G -L-->M -M-->N -M-->G -P-->Q -Q-->B -Q-->G -S-->T -T-->U -T-->G -W-->X -X-->A -X-->G -Z-->10 -Z-->G -12-->13 -13-->14 -13-->G -14-->7 -14-->16 -18-->19 -19-->G -1B-->1C -1C-->A -1C-->G diff --git a/src/misc/dependencyGraphs/mermaid-api.txt b/src/misc/dependencyGraphs/mermaid-api.txt deleted file mode 100644 index 3cb4811e..00000000 --- a/src/misc/dependencyGraphs/mermaid-api.txt +++ /dev/null @@ -1,26 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["getter"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["api.ts"] -B["response.ts"] -end -subgraph 6["controllers"] -7["scheduler.ts"] -A["fetchData.ts"] -end -subgraph 8["config"] -9["db.ts"] -end -end -3-->5 -5-->7 -5-->B -7-->9 -7-->A -A-->9 diff --git a/src/misc/dependencyGraphs/mermaid-auth.txt b/src/misc/dependencyGraphs/mermaid-auth.txt deleted file mode 100644 index 336ddedb..00000000 --- a/src/misc/dependencyGraphs/mermaid-auth.txt +++ /dev/null @@ -1,19 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["auth"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["auth.ts"] -8["response.ts"] -end -subgraph 6["controllers"] -7["auth.ts"] -end -end -3-->5 -5-->7 -5-->8 diff --git a/src/misc/dependencyGraphs/mermaid-conf.txt b/src/misc/dependencyGraphs/mermaid-conf.txt deleted file mode 100644 index 370dd892..00000000 --- a/src/misc/dependencyGraphs/mermaid-conf.txt +++ /dev/null @@ -1,26 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["setter"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["conf.ts"] -B["response.ts"] -end -subgraph 6["controllers"] -7["scheduler.ts"] -A["fetchData.ts"] -end -subgraph 8["config"] -9["db.ts"] -end -end -3-->5 -5-->7 -5-->B -7-->9 -7-->A -A-->9 diff --git a/src/misc/dependencyGraphs/mermaid-data.txt b/src/misc/dependencyGraphs/mermaid-data.txt deleted file mode 100644 index 4aa6a133..00000000 --- a/src/misc/dependencyGraphs/mermaid-data.txt +++ /dev/null @@ -1,19 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["data"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["data.ts"] -8["response.ts"] -end -subgraph 6["config"] -7["db.ts"] -end -end -3-->5 -5-->7 -5-->8 diff --git a/src/misc/dependencyGraphs/mermaid-frontend.txt b/src/misc/dependencyGraphs/mermaid-frontend.txt deleted file mode 100644 index 8dde5ce9..00000000 --- a/src/misc/dependencyGraphs/mermaid-frontend.txt +++ /dev/null @@ -1,19 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["frontendController"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["frontend.ts"] -8["response.ts"] -end -subgraph 6["controllers"] -7["frontendConfiguration.ts"] -end -end -3-->5 -5-->7 -5-->8 diff --git a/src/misc/dependencyGraphs/mermaid-graph.txt b/src/misc/dependencyGraphs/mermaid-graph.txt deleted file mode 100644 index 34484535..00000000 --- a/src/misc/dependencyGraphs/mermaid-graph.txt +++ /dev/null @@ -1,15 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["graphs"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["graph.ts"] -6["response.ts"] -end -end -3-->5 -3-->6 diff --git a/src/misc/dependencyGraphs/mermaid-ha.txt b/src/misc/dependencyGraphs/mermaid-ha.txt deleted file mode 100644 index 2c789f6c..00000000 --- a/src/misc/dependencyGraphs/mermaid-ha.txt +++ /dev/null @@ -1,31 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["highavailability"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["ha.ts"] -E["response.ts"] -end -subgraph 6["controllers"] -7["highAvailability.ts"] -end -subgraph 8["config"] -9["variables.ts"] -end -subgraph A["data"] -B["variables.json"] -end -subgraph C["typings"] -D["ha.ts"] -end -end -3-->5 -5-->7 -5-->E -7-->9 -7-->D -9-->B diff --git a/src/misc/dependencyGraphs/mermaid-notificationService.txt b/src/misc/dependencyGraphs/mermaid-notificationService.txt deleted file mode 100644 index 2bc9731c..00000000 --- a/src/misc/dependencyGraphs/mermaid-notificationService.txt +++ /dev/null @@ -1,15 +0,0 @@ -flowchart TB - -subgraph 0["src"] -subgraph 1["routes"] -subgraph 2["notifications"] -3["routes.ts"] -end -end -subgraph 4["handlers"] -5["notification.ts"] -6["response.ts"] -end -end -3-->5 -5-->6 diff --git a/src/misc/entrypoint.sh b/src/misc/entrypoint.sh deleted file mode 100755 index b352ca75..00000000 --- a/src/misc/entrypoint.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -VERSION="$(cat ./package.json | grep version | cut -d '"' -f 4)" - -if [[ "$1" = "--dev" ]]; then - node_env="development" -elif [[ "$1" = "--prod" ]]; then - node_env="production" -fi - -echo -e " -\033[1;32mWelcome to\033[0m - -\033[1;34m###### ###### #### ### ### #### ######### ###### #########\033[0m -\033[1;34m### ### ### ### ### ### ### ### ### ### ### ###\033[0m -\033[1;34m### ### ### ### ### ###### #### ### ### ### ###\033[0m -\033[1;34m### ### ### ### ### ### ### #### ### ############ ###\033[0m -\033[1;34m### ### ### ### ### ### ### #### ### ### ### ###\033[0m -\033[1;34m###### ###### #### ### ### #### ### ### ### ### \033[0m(\033[1;33mAPI - v${VERSION}\033[0m) - -\033[1;36mUseful links:\033[0m - -- Documentation: \033[1;32mhttps://outline.itsnik.de/s/dockstat\033[0m -- GitHub (Frontend): \033[1;32mhttps://github.com/its4nik/dockstat\033[0m -- GitHub (Backend): \033[1;32mhttps://github.com/its4nik/dockstatapi\033[0m - -\033[1;35mSummary:\033[0m - -DockStat and DockStatAPI are 2 fully OpenSource projects, DockStatAPI is a simple but extensible API which allows queries via a REST endpoint. - -" - -bash ./createEnvFile.sh - -NODE_ENV=${node_env} node src/server.js diff --git a/src/misc/minifyDist.sh b/src/misc/minifyDist.sh deleted file mode 100755 index 171ef095..00000000 --- a/src/misc/minifyDist.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -dist="$(pwd)/dist" - -run_script() { - npx uglifyjs --no-annotations --in-situ "$1" > /dev/null - echo "✔️ Minified : $(basename "$1")" -} - -if [ -d "$dist" ]; then - echo "::: Dist directory exists." -else - echo "::: Dist does not exist... Running npx tsc" - npx tsc -fi - -max_jobs=$(nproc) -job_count=0 - -for file in $(find "$dist" -type f -name "*.js"); do - run_script "$file" & - ((job_count++)) - - if ((job_count >= max_jobs)); then - wait - job_count=0 - fi -done - -wait - -echo - -if [[ $1 == "--build-only" ]]; then - exit 0 -fi - -node dist/server.js diff --git a/src/misc/removeUnusedDeps.sh b/src/misc/removeUnusedDeps.sh deleted file mode 100755 index 5e806df3..00000000 --- a/src/misc/removeUnusedDeps.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -echo "Creating unused dependency list" - -TMP="$(npx depcheck --ignores https,@typescript-eslint/eslint-plugin,@typescript-eslint/parser,license-checker,uglify-js,@types/supports-color,ipaddr.js,dependency-cruiser,tsx,@types/bcrypt,@types/express,@types/express-handlebars,@types/node,ts-node --quiet --oneline | tail -n 1 | tr -d '\n')" - -lines=$(echo -n "$TMP" | tr -s ' ' '\n' | wc -l) - -if ((lines == 0)); then - echo "No unused dependencies." -else - echo - echo "Removing these unused dependencies ($lines):" - for entry in $TMP; do - echo "$entry" - done - echo - - - read -n 1 -p "Delete unused dependencies? (y/n) " input - echo - - case $input in - Y|y) - COMMAND=$(echo "npm remove $TMP") - $COMMAND - exit 0 - ;; - *) - echo "Aborting" - exit 1 - ;; - esac -fi - -exit 0 diff --git a/src/plugins/example.plugin.ts b/src/plugins/example.plugin.ts new file mode 100644 index 00000000..a9ed6acc --- /dev/null +++ b/src/plugins/example.plugin.ts @@ -0,0 +1,23 @@ +import type { Plugin } from "~/typings/plugin"; +import type { ContainerInfo } from "~/typings/docker"; +import type { HostStats } from "~/typings/docker"; +import { logger } from "~/core/utils/logger"; + +const ExamplePlugin: Plugin = { + name: "Example Plugin", + async onContainerStart(containerInfo: ContainerInfo) {}, + async onContainerStop(containerInfo: ContainerInfo) {}, + async onContainerExit(containerInfo: ContainerInfo) {}, + async onContainerCreate(containerInfo: ContainerInfo) {}, + async onContainerDestroy(containerInfo: ContainerInfo) {}, + async onContainerPause(containerInfo: ContainerInfo) {}, + async onContainerUnpause(containerInfo: ContainerInfo) {}, + async onContainerRestart(containerInfo: ContainerInfo) {}, + async onContainerUpdate(containerInfo: ContainerInfo) {}, + async onContainerRename(containerInfo: ContainerInfo) {}, + async onContainerHealthStatus(containerInfo: ContainerInfo) {}, + async onHostUnreachable(HostStats: HostStats) {}, + async onHostReachableAgain(HostStats: HostStats) {}, +} satisfies Plugin; + +export default ExamplePlugin; diff --git a/src/plugins/telegram.plugin.ts b/src/plugins/telegram.plugin.ts new file mode 100644 index 00000000..cf7c376d --- /dev/null +++ b/src/plugins/telegram.plugin.ts @@ -0,0 +1,34 @@ +import type { Plugin } from "~/typings/plugin"; +import type { ContainerInfo } from "~/typings/docker"; +import { logger } from "~/core/utils/logger"; + +const TELEGRAM_BOT_TOKEN = "CHANGE_ME"; // Replace with your bot token +const TELEGRAM_CHAT_ID = "CHANGE_ME"; // Replace with your chat ID + +const TelegramNotificationPlugin: Plugin = { + name: "Telegram Notification Plugin", + async onContainerStart(containerInfo: ContainerInfo) { + const message = `Container Started: ${containerInfo.name} on ${containerInfo.hostId}`; + try { + const response = await fetch( + `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + chat_id: TELEGRAM_CHAT_ID, + text: message, + }), + }, + ); + if (!response.ok) { + logger.error(`HTTP error ${response.status}`); + } + logger.info("Telegram notification sent."); + } catch (error) { + logger.error("Failed to send Telegram notification", error as string); + } + }, +} satisfies Plugin; + +export default TelegramNotificationPlugin; diff --git a/src/routes/api-config.ts b/src/routes/api-config.ts new file mode 100644 index 00000000..e6185517 --- /dev/null +++ b/src/routes/api-config.ts @@ -0,0 +1,96 @@ +import { Elysia, t } from "elysia"; +import { dbFunctions } from "~/core/database/repository"; +import { logger } from "~/core/utils/logger"; +import { responseHandler } from "~/core/utils/respone-handler"; +import { config } from "~/typings/database"; +import { + version, + authorEmail, + authorName, + authorWebsite, + contributors, + dependencies, + description, + devDependencies, + license, +} from "~/core/utils/package-json"; + +export const apiConfigRoutes = new Elysia({ prefix: "/config" }) + .get( + "/get", + async ({ set }) => { + try { + const data = dbFunctions.getConfig() as config[]; + const distinct = data[0]; + set.status = 200; + set.headers["Content-Type"] = "application/json"; + logger.debug("Fetched backend config"); + return distinct; + } catch (error) { + return responseHandler.error( + set, + "Error getting the DockStatAPI config", + error as string, + ); + } + }, + { + tags: ["Management"], + }, + ) + .post( + "/update", + async ({ set, body }) => { + try { + const { polling_rate, fetching_interval, keep_data_for } = body; + set.headers["Content-Type"] = "application/json"; + dbFunctions.updateConfig( + polling_rate, + fetching_interval, + keep_data_for, + ); + return responseHandler.ok(set, "Updated DockStatAPI config"); + } catch (error) { + return responseHandler.error( + set, + "Error updating the DockStatAPI config", + error as string, + ); + } + }, + { + body: t.Object({ + polling_rate: t.Number(), + fetching_interval: t.Number(), + keep_data_for: t.Number(), + }), + tags: ["Management"], + }, + ) + .get("/package", async ({ set }) => { + try { + logger.debug("Fetching package.json"); + return { + version: version, + description: description, + license: license, + authorName: authorName, + authorEmail: authorEmail, + authorWebsite: authorWebsite, + contributors: contributors, + dependencies: dependencies, + devDependencies: devDependencies, + }; + + } catch (error) { + return responseHandler.error( + set, + error as string, + "Error while reading package.json", + ); + } + }, + { + tags: ["Management"], + }, + ); diff --git a/src/routes/auth/routes.ts b/src/routes/auth/routes.ts deleted file mode 100644 index 03549bfa..00000000 --- a/src/routes/auth/routes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Router, Request, Response } from "express"; -import { createAuthenticationHandler } from "../../handlers/auth"; - -const router = Router(); - -router.post("/enable", async (req: Request, res: Response): Promise => { - const password = req.query.password as string; - const handler = createAuthenticationHandler(req, res); - await handler.enable(password); -}); - -router.post("/disable", async (req: Request, res: Response): Promise => { - const password = req.query.password as string; - const handler = createAuthenticationHandler(req, res); - await handler.disable(password); -}); - -export default router; diff --git a/src/routes/data/routes.ts b/src/routes/data/routes.ts deleted file mode 100644 index 93c4610b..00000000 --- a/src/routes/data/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import express, { Request, Response } from "express"; -const router = express.Router(); -import { createDatabaseHandler } from "../../handlers/data"; - -router.get("/latest", (req: Request, res: Response) => { - const DatabaseHandler = createDatabaseHandler(req, res); - return DatabaseHandler.latest(); -}); - -router.get("/all", (req: Request, res: Response) => { - const DatabaseHandler = createDatabaseHandler(req, res); - return DatabaseHandler.all(); -}); - -router.delete("/clear", (req: Request, res: Response) => { - const DatabaseHandler = createDatabaseHandler(req, res); - return DatabaseHandler.clear(); -}); - -export default router; diff --git a/src/routes/docker-manager.ts b/src/routes/docker-manager.ts new file mode 100644 index 00000000..eb53fdb9 --- /dev/null +++ b/src/routes/docker-manager.ts @@ -0,0 +1,82 @@ +import { Elysia, t } from "elysia"; +import { dbFunctions } from "~/core/database/repository"; +import { logger } from "~/core/utils/logger"; +import { responseHandler } from "~/core/utils/respone-handler"; + +export const dockerRoutes = new Elysia({ prefix: "/docker-config" }) + .post( + "/add-host", + async ({ set, body }) => { + try { + const { name, url, secure } = body; + set.headers["Content-Type"] = "application/json"; + dbFunctions.addDockerHost(name, url, secure); + return responseHandler.ok(set, `Added docker host (${name})`); + } catch (error: unknown) { + return responseHandler.error( + set, + "Error adding docker Host", + error as string, + ); + } + }, + { + detail: { + tags: ["Management"], + }, + body: t.Object({ + name: t.String(), + url: t.String(), + secure: t.Boolean(), + }), + }, + ) + + .post( + "/update-host", + async ({ set, body }) => { + try { + const { name, url, secure } = body; + dbFunctions.updateDockerHost(name, url, secure); + } catch (error) { + return responseHandler.error( + set, + error as string, + "Failed to update host", + ); + } + }, + { + detail: { + tags: ["Management"], + }, + body: t.Object({ + name: t.String(), + url: t.String(), + secure: t.Boolean(), + }), + }, + ) + + .get( + "/hosts", + async ({ set }) => { + try { + const dockerHosts = dbFunctions.getDockerHosts(); + set.headers["Content-Type"] = "application/json"; + logger.debug("Retrieved docker hosts"); + return dockerHosts; + } catch (error) { + return responseHandler.error( + set, + error as string, + "Failed to retrieve hosts", + ); + } + }, + { + detail: { + tags: ["Management"], + }, + }, + ); diff --git a/src/routes/docker-stats.ts b/src/routes/docker-stats.ts new file mode 100644 index 00000000..d85bfc1f --- /dev/null +++ b/src/routes/docker-stats.ts @@ -0,0 +1,157 @@ +import Docker from "dockerode"; +import { Elysia } from "elysia"; +import { dbFunctions } from "~/core/database/repository"; +import { getDockerClient } from "~/core/docker/client"; +import { + calculateCpuPercent, + calculateMemoryUsage, +} from "~/core/utils/calculations"; +import { logger } from "~/core/utils/logger"; +import { responseHandler } from "~/core/utils/respone-handler"; +import type { ContainerInfo, DockerHost, HostStats } from "~/typings/docker"; +import type { DockerInfo } from "~/typings/dockerode"; + +export const dockerStatsRoutes = new Elysia({ prefix: "/docker" }) + .get( + "/containers", + async ({ set }) => { + try { + const hosts = dbFunctions.getDockerHosts() as DockerHost[]; + const containers: ContainerInfo[] = []; + + await Promise.all( + hosts.map(async (host) => { + try { + const docker = getDockerClient(host); + try { + await docker.ping(); + } catch (pingError) { + return responseHandler.error( + set, + pingError as string, + "Docker host connection failed", + ); + } + + const hostContainers = await docker.listContainers({ all: true }); + + await Promise.all( + hostContainers.map(async (containerInfo) => { + try { + const container = docker.getContainer(containerInfo.Id); + const stats = await new Promise( + (resolve, reject) => { + container.stats({ stream: false }, (error, stats) => { + if (error) { + return responseHandler.reject( + set, + reject, + "An error occurred", + error, + ); + } + if (!stats) { + return responseHandler.reject( + set, + reject, + "No stats available", + ); + } + resolve(stats); + }); + }, + ); + + containers.push({ + id: containerInfo.Id, + hostId: host.name, + name: containerInfo.Names[0].replace(/^\//, ""), + image: containerInfo.Image, + status: containerInfo.Status, + state: containerInfo.State, + cpuUsage: calculateCpuPercent(stats), + memoryUsage: calculateMemoryUsage(stats), + }); + } catch (containerError) { + logger.error( + "Error fetching container stats,", + containerError, + ); + } + }), + ); + logger.debug(`Fetched stats for ${host.name}`); + } catch (hostError) { + logger.error("Error fetching containers for host,", hostError); + } + }), + ); + + set.headers["Content-Type"] = "application/json"; + logger.debug("Fetched all containers across all hosts"); + return { containers }; + } catch (error) { + return responseHandler.error( + set, + error as string, + "Failed to retrieve containers", + ); + } + }, + { + detail: { + tags: ["Statistics"], + }, + }, + ) + + .get( + "/hosts/:id", + async ({ params, set }) => { + try { + const hosts = dbFunctions.getDockerHosts() as DockerHost[]; + const host = hosts.find((h) => h.name === params.id); + + if (!host) { + return responseHandler.simple_error( + set, + `Host (${params.id}) not found`, + ); + } + + const docker = getDockerClient(host); + const info: DockerInfo = await docker.info(); + + const config: HostStats = { + hostId: host.name, + dockerVersion: info.ServerVersion, + apiVersion: info.Driver, + os: info.OperatingSystem, + architecture: info.Architecture, + totalMemory: info.MemTotal, + totalCPU: info.NCPU, + labels: info.Labels, + images: info.Images, + containers: info.Containers, + containersPaused: info.ContainersPaused, + containersRunning: info.ContainersRunning, + containersStopped: info.ContainersStopped, + }; + + set.headers["Content-Type"] = "application/json"; + logger.debug(`Fetched config for ${host.name}`); + return config; + } catch (error) { + return responseHandler.error( + set, + error as string, + "Failed to retrieve host config", + ); + } + }, + { + detail: { + tags: ["Statistics"], + }, + }, + ); diff --git a/src/routes/docker-websocket.ts b/src/routes/docker-websocket.ts new file mode 100644 index 00000000..43c8038a --- /dev/null +++ b/src/routes/docker-websocket.ts @@ -0,0 +1,240 @@ +import type { StatusMap } from "elysia"; +import { Elysia } from "elysia"; +import type { HTTPHeaders } from "elysia/dist/types"; +import { dbFunctions } from "~/core/database/repository"; +import { getDockerClient } from "~/core/docker/client"; +import { + calculateCpuPercent, + calculateMemoryUsage, +} from "~/core/utils/calculations"; +import { logger } from "~/core/utils/logger"; +import { responseHandler } from "~/core/utils/respone-handler"; +import type { DockerHost } from "~/typings/docker"; +import split2 from "split2"; +import type { Readable } from "stream"; +import type { streams } from "~/typings/websocket"; + +interface ExtendedWebSocket extends WebSocket { + isOpen: boolean; + streams: any[]; + heartbeat: NodeJS.Timeout | null; +} + +const set: { headers: HTTPHeaders; status?: number | keyof StatusMap } = { + headers: {}, +}; + +export const dockerWebsocketRoutes = new Elysia({ prefix: "/docker" }).ws( + "/stats", + { + async open(socket) { + socket.send(JSON.stringify({ message: "Connection established" })); + let hosts: DockerHost[]; + + (socket as unknown as ExtendedWebSocket).isOpen = true; + (socket as unknown as ExtendedWebSocket).streams = []; + (socket as unknown as ExtendedWebSocket).heartbeat = null; // Add heartbeat reference + + logger.info(`Opened WebSocket (${socket.id})`); + + try { + hosts = dbFunctions.getDockerHosts(); + logger.debug( + `Retrieved ${hosts.length} docker host(s) from the database`, + ); + } catch (error: unknown) { + const errResponse = responseHandler.error( + set, + (error as Error).message, + "Failed to retrieve Docker hosts", + 500, + ); + logger.error( + `Error retrieving Docker hosts: ${(error as Error).message}`, + ); + socket.send(JSON.stringify(errResponse)); + return; + } + + // Add heartbeat using WebSocket protocol-level ping + (socket as any).heartbeat = setInterval(() => { + if (!(socket as unknown as ExtendedWebSocket).isOpen) { + clearInterval((socket as any).heartbeat); + return; + } + socket.ping(); // Use WebSocket protocol ping + }, 30000); + + for (const host of hosts) { + if (!(socket as unknown as ExtendedWebSocket).isOpen) { + break + }; + + logger.debug(`Processing host: ${host.name}`); + + try { + const docker = getDockerClient(host); + await docker.ping(); + logger.debug(`Ping successful for host: ${host.name}`); + logger.debug(`Listing containers for host: ${host.name}`); + const containers = await docker.listContainers(); + logger.debug( + `Found ${containers.length} container(s) on host ${host.name}`, + ); + + for (const containerInfo of containers) { + if (!(socket as unknown as ExtendedWebSocket).isOpen) { + break + }; + + logger.debug( + `Processing container ${containerInfo.Id} on host ${host.name}`, + ); + const container = docker.getContainer(containerInfo.Id); + try { + logger.debug( + `Starting stats stream for container ${containerInfo.Id} on host ${host.name}`, + ); + const statsStream = (await container.stats({ + stream: true, + })) as Readable; + const splitStream = split2(); + + // Store both streams for cleanup + (socket as unknown as ExtendedWebSocket).streams.push({ statsStream, splitStream }); + + // Handle stream lifecycle + statsStream + .on("close", () => { + logger.debug(`Stats stream closed for ${containerInfo.Id}`); + splitStream.destroy(); + }) + .on("end", () => { + logger.debug(`Stats stream ended for ${containerInfo.Id}`); + splitStream.destroy(); + }); + + statsStream + .pipe(splitStream) + .on("data", (line: string) => { + // 1 = OPEN state + if (socket.readyState !== 1) { + return + }; + if (!line) { + return + }; + try { + const stats = JSON.parse(line); + const cpuUsage = calculateCpuPercent(stats); + const memoryUsage = calculateMemoryUsage(stats); + + const data = { + id: containerInfo.Id, + hostId: host.name, + name: containerInfo.Names[0].replace(/^\//, ""), + image: containerInfo.Image, + status: containerInfo.Status, + state: containerInfo.State, + cpuUsage, + memoryUsage, + }; + socket.send(JSON.stringify(data)); + } catch (parseErr: any) { + logger.error( + `Failed to parse stats for container ${containerInfo.Id} on host ${host.name}: ${parseErr.message}`, + ); + } + }) + .on("error", (err: Error) => { + logger.error( + `Stats stream error for container ${containerInfo.Id} on host ${host.name}: ${err.message}`, + ); + if (socket.readyState === 1) { + socket.send( + JSON.stringify({ + hostId: host.name, + containerId: containerInfo.Id, + error: `Stats stream error for container ${containerInfo.Id} on host ${host.name}`, + }), + ); + } + statsStream.destroy(); + }); + } catch (streamErr: any) { + const errMsg = `Failed to start stats stream for container ${containerInfo.Id}`; + logger.error( + `Failed to start stats stream for container ${containerInfo.Id} on host ${host.name}: ${streamErr.message}`, + ); + if (socket.readyState === 1) { + socket.send( + JSON.stringify({ + hostId: host.name, + containerId: containerInfo.Id, + error: errMsg, + }), + ); + } + } + } + } catch (err: any) { + logger.error( + `Failed to list containers for host ${host.name}: ${err.message}`, + ); + const errResponse = responseHandler.error( + set, + err.message, + `Failed to list containers for host ${host.name}`, + 500, + ); + if (socket.readyState === 1) { + socket.send( + JSON.stringify({ + hostId: host.name, + error: errResponse.error, + }), + ); + } + } + } + }, + + message(_, message) { + if (message === "pong") { + return + }; + }, + + close(socket, code, reason) { + logger.info(`Closing SplitStream and WebSocket (${socket.id})`); + const wasOpen = (socket as unknown as ExtendedWebSocket).isOpen; + (socket as unknown as ExtendedWebSocket).isOpen = false; + + // Immediate heartbeat cleanup + clearInterval((socket as any).heartbeat); + + // Force-close streams using destructor pattern + const streams: streams[] = (socket as unknown as ExtendedWebSocket).streams || []; + streams.forEach(({ statsStream, splitStream }) => { + try { + // Immediate pipeline breakdown + statsStream.unpipe(splitStream); + statsStream.destroy(new Error("WebSocket closed")); + splitStream.destroy(new Error("WebSocket closed")); + + // Remove all potential listeners + statsStream.removeAllListeners(); + splitStream.removeAllListeners(); + } catch (err) { + logger.error(`Stream cleanup error: ${err}`); + } + }); + + if (wasOpen) { + logger.info( + `Closed WebSocket (${socket.id}) - Code: ${code} - Reason: ${reason}`, + ); + } + }, + }, +); diff --git a/src/routes/frontendController/routes.ts b/src/routes/frontendController/routes.ts deleted file mode 100644 index 723afa47..00000000 --- a/src/routes/frontendController/routes.ts +++ /dev/null @@ -1,76 +0,0 @@ -import express from "express"; -const router = express.Router(); -import { createFrontendHandler } from "../../handlers/frontend"; - -router.post("/show/:containerName", async (req, res) => { - const FrontendHandler = createFrontendHandler(req, res); - const containerName = req.params.containerName; - return FrontendHandler.show(containerName); -}); - -router.post("/tag/:containerName/:tag", async (req, res) => { - const { containerName, tag } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.addTag(containerName, tag); -}); - -router.post("/pin/:containerName", async (req, res) => { - const { containerName } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.pin(containerName); -}); - -router.post("/add-link/:containerName/:link", async (req, res) => { - const { containerName, link } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.addLink(containerName, link); -}); - -router.post( - "/add-icon/:containerName/:icon/:useCustomIcon", - async (req, res) => { - const { containerName, icon, useCustomIcon } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.addIcon(containerName, icon, useCustomIcon); - }, -); - -/* - ____ _____ _ _____ _____ _____ -| _ \| ____| | | ____|_ _| ____| -| | | | _| | | | _| | | | _| -| |_| | |___| |___| |___ | | | |___ -|____/|_____|_____|_____| |_| |_____| -*/ - -router.delete("/hide/:containerName", async (req, res) => { - const { containerName } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.hide(containerName); -}); - -router.delete("/remove-tag/:containerName/:tag", async (req, res) => { - const { containerName, tag } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.removeTag(containerName, tag); -}); - -router.delete("/unpin/:containerName", async (req, res) => { - const { containerName } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.unPin(containerName); -}); - -router.delete("/remove-link/:containerName", async (req, res) => { - const { containerName } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.removeLink(containerName); -}); - -router.delete("/remove-icon/:containerName", async (req, res) => { - const { containerName } = req.params; - const FrontendHandler = createFrontendHandler(req, res); - return FrontendHandler.removeIcon(containerName); -}); - -export default router; diff --git a/src/routes/getter/routes.ts b/src/routes/getter/routes.ts deleted file mode 100644 index d08ae511..00000000 --- a/src/routes/getter/routes.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Router, Request, Response } from "express"; -import { createApiHandler } from "../../handlers/api"; -const router = Router(); - -router.get("/hosts", (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.hosts(); -}); - -router.get("/system", (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.system(); -}); - -router.get("/host/:hostName/stats", async (req: Request, res: Response) => { - const { hostName } = req.params; - const ApiHandler = createApiHandler(req, res); - return ApiHandler.hostStats(hostName); -}); - -router.get("/containers", async (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.containers(); -}); - -router.get("/config", async (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.config(); -}); - -router.get("/current-schedule", (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.currentSchedule(); -}); - -router.get("/status", async (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.status(); -}); - -router.get("/frontend-config", (req: Request, res: Response) => { - const ApiHandler = createApiHandler(req, res); - return ApiHandler.frontendConfig(); -}); - -export default router; diff --git a/src/routes/graphs/routes.ts b/src/routes/graphs/routes.ts deleted file mode 100644 index fcaa7983..00000000 --- a/src/routes/graphs/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Request, Response, Router } from "express"; -import { createResponseHandler } from "../../handlers/response"; -import path from "path"; -import { rateLimitedReadFile } from "../../utils/rateLimitFS"; -const router = Router(); - -router.get("/json", async (req: Request, res: Response) => { - const ResponseHandler = createResponseHandler(res); - try { - const data = await rateLimitedReadFile( - path.join(__dirname, "/../../.." + "/src/data/graph.json"), - ); - return ResponseHandler.rawData(data, "Graph JSON fetched"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - return ResponseHandler.critical(errorMsg); - } -}); - -export default router; diff --git a/src/routes/highavailability/routes.ts b/src/routes/highavailability/routes.ts deleted file mode 100644 index d4adc466..00000000 --- a/src/routes/highavailability/routes.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Router, Request, Response } from "express"; -import { SyncRequestBody } from "../../typings/syncRequestBody"; -import { createHaHandler } from "../../handlers/ha"; -const router = Router(); - -router.get("/config", async (req: Request, res: Response) => { - const HaHandler = createHaHandler(req, res); - return HaHandler.config(); -}); - -router.post( - "/sync", - async ( - req: Request<{}, {}, SyncRequestBody>, // eslint-disable-line - res: Response, - ): Promise => { - const HaHandler = createHaHandler(req, res); - return HaHandler.sync(req); - }, -); - -router.get("/prepare-sync", async (req: Request, res: Response) => { - const HaHandler = createHaHandler(req, res); - return HaHandler.prepare(); -}); - -export default router; diff --git a/src/routes/logs.ts b/src/routes/logs.ts new file mode 100644 index 00000000..a8cae1c5 --- /dev/null +++ b/src/routes/logs.ts @@ -0,0 +1,88 @@ +import { Elysia } from "elysia"; +import { dbFunctions } from "~/core/database/repository"; +import { logger } from "~/core/utils/logger"; + +export const backendLogs = new Elysia({ prefix: "/logs" }) + .get( + "/", + async ({ set }) => { + try { + const logs = dbFunctions.getAllLogs(); + set.headers["Content-Type"] = "application/json"; + logger.debug(`Retrieved all logs`); + return logs; + } catch (error) { + set.status = 500; + logger.error("Failed to retrieve logs,", error); + return { error: "Failed to retrieve logs" }; + } + }, + { + detail: { + tags: ["Management"], + }, + }, + ) + + .get( + "/:level", + async ({ params: { level }, set }) => { + try { + const logs = dbFunctions.getLogsByLevel(level); + set.headers["Content-Type"] = "application/json"; + logger.debug(`Retrieved logs (level: ${level})`); + return logs; + } catch (error) { + set.status = 500; + logger.error("Failed to retrieve logs"); + return { error: "Failed to retrieve logs" }; + } + }, + { + detail: { + tags: ["Management"], + }, + }, + ) + + .delete( + "/", + async ({ set }) => { + try { + set.status = 200; + set.headers["Content-Type"] = "application/json"; + dbFunctions.clearAllLogs(); + return { success: true }; + } catch (error) { + set.status = 500; + logger.error("Could not delete all logs,", error); + return { error: "Could not delete all logs" }; + } + }, + { + detail: { + tags: ["Management"], + }, + }, + ) + + .delete( + "/:level", + async ({ params: { level }, set }) => { + try { + dbFunctions.clearLogsByLevel(level); + set.headers["Content-Type"] = "application/json"; + logger.debug(`Cleared all logs with level: ${level}`); + return { success: true }; + } catch (error) { + set.status = 500; + logger.error("Could not clear logs with level", level, ",", error); + return { error: "Failed to retrieve logs" }; + } + }, + { + detail: { + tags: ["Management"], + }, + }, + ); diff --git a/src/routes/notifications/routes.ts b/src/routes/notifications/routes.ts deleted file mode 100644 index 13b754bd..00000000 --- a/src/routes/notifications/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Request, Response, Router } from "express"; -import { createNotificationHandler } from "../../handlers/notification"; -const router = Router(); - -router.get("/get-template", (req: Request, res: Response) => { - const NotificationHandler = createNotificationHandler(req, res); - return NotificationHandler.getTemplate(); -}); - -router.post("/set-template", (req: Request, res: Response): void => { - const NotificationHandler = createNotificationHandler(req, res); - return NotificationHandler.setTemplate(req); -}); - -router.post("/test/:type/:containerId", async (req: Request, res: Response) => { - const NotificationHandler = createNotificationHandler(req, res); - NotificationHandler.test(req); -}); - -export default router; diff --git a/src/routes/setter/routes.ts b/src/routes/setter/routes.ts deleted file mode 100644 index 16150293..00000000 --- a/src/routes/setter/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import express, { Router, Request, Response } from "express"; -const router: Router = express.Router(); -import { createConfHandler } from "../../handlers/conf"; - -router.put("/addHost", async (req: Request, res: Response): Promise => { - const ConfHandler = createConfHandler(req, res); - return ConfHandler.addHost(req); -}); - -router.delete("/removeHost", (req: Request, res: Response): void => { - const ConfHandler = createConfHandler(req, res); - return ConfHandler.removeHost(req); -}); - -router.put("/scheduler", (req: Request, res: Response) => { - const ConfHandler = createConfHandler(req, res); - return ConfHandler.scheduler(req); -}); - -export default router; diff --git a/src/routes/stack/routes.ts b/src/routes/stack/routes.ts deleted file mode 100644 index 8f9b9ae8..00000000 --- a/src/routes/stack/routes.ts +++ /dev/null @@ -1,35 +0,0 @@ -import express, { Router, Request, Response } from "express"; -const router: Router = express.Router(); -import { createStackHandler } from "../../handlers/stack"; - -router.post("/create/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return StackHandler.createStack(req, res); -}); - -router.post("/start/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return StackHandler.start(req, res); -}); - -router.post("/stop/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return StackHandler.stop(req, res); -}); - -router.get("/get/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return await StackHandler.stackCompose(req, res); -}); - -router.post("/set-env/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return await StackHandler.setStackEnv(req, res); -}); - -router.get("/get-env/:name", async (req: Request, res: Response) => { - const StackHandler = createStackHandler(req, res); - return await StackHandler.getStackEnv(req, res); -}); - -export default router; diff --git a/src/routes/stacks.ts b/src/routes/stacks.ts new file mode 100644 index 00000000..600dec55 --- /dev/null +++ b/src/routes/stacks.ts @@ -0,0 +1,239 @@ +import { Elysia, error, t } from "elysia"; +import { responseHandler } from "~/core/utils/respone-handler"; +import { + deployStack, + stopStack, + pullStackImages, + restartStack, + getStackStatus, + startStack +} from "~/core/stacks/controller"; +import { dbFunctions } from "~/core/database/repository"; +import { logger } from "~/core/utils/logger"; + +export const stackRoutes = new Elysia({ prefix: "/stacks" }) + .post( + "/deploy", + async ({ set, body }) => { + try { + const isCustom = body.isCustom || false; + + + const image_updates = body.image_updates || false; + + + let missingParams: string[] = []; + if (!body.compose_spec) { + missingParams.push("compose_spec"); + } + if (!body.automatic_reboot_on_error) { + missingParams.push("automatic_reboot_on_error"); + } + if (!body.source) { + missingParams.push("source"); + } + if (!body.name) { + missingParams.push("name"); + } + + if (missingParams.length > 0) { + const errMsg = `Missing values of: ${missingParams.join("; ")}`; + return responseHandler.error(set, errMsg, errMsg); + } + + await deployStack( + body.compose_spec, + body.name, + body.version, + body.source, + body.automatic_reboot_on_error, + isCustom, + image_updates, + body.stack_prefix + ); + logger.info(`Deployed Stack (${body.name})`) + return responseHandler.ok( + set, + `Stack ${body.name} deployed successfully` + ); + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error deploying stack" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + body: t.Object({ + compose_spec: t.Any(), + name: t.String(), + version: t.Number(), + automatic_reboot_on_error: t.Boolean(), + isCustom: t.Boolean(), + image_updates: t.Boolean(), + source: t.String(), + stack_prefix: t.Optional(t.String()), + }), + } + ) + .post( + "/start", + async ({ set, body }) => { + try { + if (!body.stack) { + throw new Error("Stack needed") + } + await startStack(body.stack); + logger.info(`Started Stack (${body.stack})`) + return responseHandler.ok( + set, + `Stack ${body.stack} started successfully` + ); + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error starting stack" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + body: t.Object({ + stack: t.Any(), + }), + } + ) + .post( + "/stop", + async ({ set, body }) => { + try { + if (!body.stack) { + throw new Error("Stack needed") + } + await stopStack(body.stack); + logger.info(`Stopped Stack (${body.stack})`) + return responseHandler.ok( + set, + `Stack ${body.stack} stopped successfully` + ); + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error stopping stack" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + body: t.Object({ + stack: t.Any(), + }), + } + ) + .post( + "/restart", + async ({ set, body }) => { + try { + if (!body.stack) { + throw new Error("Stack needed") + } + await restartStack(body.stack); + logger.info(`Restarted Stack (${body.stack})`) + return responseHandler.ok( + set, + `Stack ${body.stack} restarted successfully` + ); + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error restarting stack" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + body: t.Object({ + stack: t.Any(), + }), + } + ) + .post( + "/pull-images", + async ({ set, body }) => { + try { + if (!body.stack) { + throw new Error("Stack needed") + } + await pullStackImages(body.stack); + logger.info(`Pulled Stack images (${body.stack})`) + return responseHandler.ok( + set, + `Images for stack ${body.stack} pulled successfully` + ); + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error pulling images" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + body: t.Object({ + stack: t.Any(), + }), + } + ) + .get( + "/status", + async ({ set, query }) => { + try { + if (!query.stack_name) { + throw new Error("Stack needed") + } + logger.debug(query.stack_name) + const status = await getStackStatus(query.stack_name); + const res = responseHandler.ok( + set, + `Stack ${query.stack_name} status retrieved successfully` + ); + logger.info("Fetched Stack status") + return { ...res, status: status }; + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error getting stack status" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + query: t.Object({ + stack_name: t.Any(), + }), + } + ) + .get("/", async ({ set }) => { + try { + const stacks = dbFunctions.getStacks(); + logger.info("Fetched Stacks") + return stacks; + } catch (error: any) { + return responseHandler.error( + set, + error.message || error, + "Error getting stacks" + ); + } + }, + { + detail: { tags: ["Stacks"] }, + } + ); diff --git a/src/sample-variable.json b/src/sample-variable.json deleted file mode 100644 index f507796b..00000000 --- a/src/sample-variable.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "VERSION": "", - "RUNNING_IN_DOCKER": "", - "TRUSTED_PROXIES": "", - "HA_MASTER": "", - "HA_MASTER_IP": "", - "HA_NODE": "", - "HA_UNSAFE": "", - "DISCORD_WEBHOOK_URL": "", - "EMAIL_SENDER": "", - "EMAIL_RECIPIENT": "", - "EMAIL_PASSWORD": "", - "EMAIL_SERVICE": "", - "PUSHBULLET_ACCESS_TOKEN": "", - "PUSHOVER_USER_KEY": "", - "PUSHOVER_API_TOKEN": "", - "SLACK_WEBHOOK_URL": "", - "TELEGRAM_BOT_TOKEN": "", - "TELEGRAM_CHAT_ID": "", - "WHATSAPP_API_URL": "", - "WHATSAPP_RECIPIENT": "", - "AUTOMATIC_ENVIRONMENT_FILE_MANAGEMENT": "true", - "LOG_LEVEL": "info" -} diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index edcb2ec5..00000000 --- a/src/server.ts +++ /dev/null @@ -1,18 +0,0 @@ -import express from "express"; -import initializeApp from "./init"; -import writeUserConf from "./config/hostsystem"; -import { startServer } from "./utils/startServer"; -import http from "http"; - -const port: number = parseInt(process.env.PORT || "9876"); -const app = express(); -const server = http.createServer(app); - -initializeApp(app, server); - -if (process.env.NODE_ENV !== "testing") { - writeUserConf(port); - startServer(app, server, port); -} - -export default app; \ No newline at end of file diff --git a/src/typings/atomicWrite.ts b/src/typings/atomicWrite.ts deleted file mode 100644 index 1f4bfb4a..00000000 --- a/src/typings/atomicWrite.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface AtomicWriteOptions { - mode?: number; - exclusive?: boolean; -} - -export { AtomicWriteOptions }; diff --git a/src/typings/database.ts b/src/typings/database.ts new file mode 100644 index 00000000..3d95b353 --- /dev/null +++ b/src/typings/database.ts @@ -0,0 +1,25 @@ +interface backend_log_entries { + timestamp: string; + level: string; + message: string; + file: string; + line: number; +} + +interface config { + polling_rate: number; + keep_data_for: number; + fetching_interval: number; +} +interface stacks_config { + name: string; + version: number; + custom: boolean; + source: string; + container_count: number; + stack_prefix: string; + automatic_reboot_on_error: boolean; + image_updates: boolean; +} + +export type { backend_log_entries, config, stacks_config }; diff --git a/src/typings/docker-compose.ts b/src/typings/docker-compose.ts new file mode 100644 index 00000000..a554c21c --- /dev/null +++ b/src/typings/docker-compose.ts @@ -0,0 +1,393 @@ +export interface Stack { + compose_spec: ComposeSpec; + name: string + version: number; + source: string; +} + +export interface ComposeSpec { + version?: string; + name?: string; + include?: Include[]; + services?: { [key: string]: Service }; + networks?: { [key: string]: Network }; + volumes?: { [key: string]: Volume }; + secrets?: { [key: string]: Secret }; + configs?: { [key: string]: Config }; + [key: `x-${string}`]: any; +} + +type Include = string | { path: string | string[]; env_file?: string | string[]; project_directory?: string }; + +interface Service { + develop?: Development | null; + deploy?: Deployment | null; + annotations?: ListOrDict; + attach?: boolean | string; + build?: string | { + context?: string; + dockerfile?: string; + dockerfile_inline?: string; + entitlements?: string[]; + args?: ListOrDict; + ssh?: ListOrDict; + labels?: ListOrDict; + cache_from?: string[]; + cache_to?: string[]; + no_cache?: boolean | string; + additional_contexts?: ListOrDict; + network?: string; + pull?: boolean | string; + target?: string; + shm_size?: number | string; + extra_hosts?: ExtraHosts; + isolation?: string; + privileged?: boolean | string; + secrets?: ServiceConfigOrSecret[]; + tags?: string[]; + ulimits?: Ulimits; + platforms?: string[]; + [key: `x-${string}`]: any; + }; + blkio_config?: { + device_read_bps?: BlkioLimit[]; + device_read_iops?: BlkioLimit[]; + device_write_bps?: BlkioLimit[]; + device_write_iops?: BlkioLimit[]; + weight?: number | string; + weight_device?: BlkioWeight[]; + }; + cap_add?: string[]; + cap_drop?: string[]; + cgroup?: 'host' | 'private'; + cgroup_parent?: string; + command?: Command; + configs?: ServiceConfigOrSecret[]; + container_name?: string; + cpu_count?: string | number; + cpu_percent?: string | number; + cpu_shares?: number | string; + cpu_quota?: number | string; + cpu_period?: number | string; + cpu_rt_period?: number | string; + cpu_rt_runtime?: number | string; + cpus?: number | string; + cpuset?: string; + credential_spec?: { + config?: string; + file?: string; + registry?: string; + [key: `x-${string}`]: any; + }; + depends_on?: string[] | { + [service: string]: { + condition: 'service_started' | 'service_healthy' | 'service_completed_successfully'; + restart?: boolean | string; + required?: boolean; + [key: `x-${string}`]: any; + } + }; + device_cgroup_rules?: string[]; + devices?: (string | { + source: string; + target?: string; + permissions?: string; + [key: `x-${string}`]: any; + })[]; + dns?: StringOrList; + dns_opt?: string[]; + dns_search?: StringOrList; + domainname?: string; + entrypoint?: Command; + env_file?: EnvFile; + label_file?: string | string[]; + environment?: ListOrDict; + expose?: (string | number)[]; + extends?: string | { service: string; file?: string }; + external_links?: string[]; + extra_hosts?: ExtraHosts; + gpus?: 'all' | Array<{ + capabilities?: string[]; + count?: string | number; + device_ids?: string[]; + driver?: string; + options?: ListOrDict; + [key: `x-${string}`]: any; + }>; + group_add?: (string | number)[]; + healthcheck?: Healthcheck; + hostname?: string; + image?: string; + init?: boolean | string; + ipc?: string; + isolation?: string; + labels?: ListOrDict; + links?: string[]; + logging?: { + driver?: string; + options?: { [key: string]: string | number | null }; + [key: `x-${string}`]: any; + }; + mac_address?: string; + mem_limit?: number | string; + mem_reservation?: string | number; + mem_swappiness?: number | string; + memswap_limit?: number | string; + network_mode?: string; + networks?: string[] | { + [network: string]: { + aliases?: string[]; + ipv4_address?: string; + ipv6_address?: string; + link_local_ips?: string[]; + mac_address?: string; + driver_opts?: { [key: string]: string | number }; + priority?: number; + [key: `x-${string}`]: any; + } | null; + }; + oom_kill_disable?: boolean | string; + oom_score_adj?: string | number; + pid?: string | null; + pids_limit?: number | string; + platform?: string; + ports?: (number | string | { + name?: string; + mode?: string; + host_ip?: string; + target?: number | string; + published?: string | number; + protocol?: string; + app_protocol?: string; + [key: `x-${string}`]: any; + })[]; + post_start?: ServiceHook[]; + pre_stop?: ServiceHook[]; + privileged?: boolean | string; + profiles?: string[]; + pull_policy?: 'always' | 'never' | 'if_not_present' | 'build' | 'missing'; + read_only?: boolean | string; + restart?: string; + runtime?: string; + scale?: number | string; + security_opt?: string[]; + shm_size?: number | string; + secrets?: ServiceConfigOrSecret[]; + sysctls?: ListOrDict; + stdin_open?: boolean | string; + stop_grace_period?: string; + stop_signal?: string; + storage_opt?: object; + tmpfs?: StringOrList; + tty?: boolean | string; + ulimits?: Ulimits; + user?: string; + uts?: string; + userns_mode?: string; + volumes?: (string | { + type: string; + source?: string; + target?: string; + read_only?: boolean | string; + consistency?: string; + bind?: { + propagation?: string; + create_host_path?: boolean | string; + recursive?: 'enabled' | 'disabled' | 'writable' | 'readonly'; + selinux?: 'z' | 'Z'; + [key: `x-${string}`]: any; + }; + volume?: { + nocopy?: boolean | string; + subpath?: string; + [key: `x-${string}`]: any; + }; + tmpfs?: { + size?: number | string; + mode?: number | string; + [key: `x-${string}`]: any; + }; + [key: `x-${string}`]: any; + })[]; + volumes_from?: string[]; + working_dir?: string; + [key: `x-${string}`]: any; +} + +interface Healthcheck { + disable?: boolean | string; + interval?: string; + retries?: number | string; + test?: string | string[]; + timeout?: string; + start_period?: string; + start_interval?: string; + [key: `x-${string}`]: any; +} + +interface Development { + watch?: Array<{ + path: string; + action: 'rebuild' | 'sync' | 'restart' | 'sync+restart' | 'sync+exec'; + ignore?: string[]; + target?: string; + exec?: ServiceHook; + [key: `x-${string}`]: any; + }>; + [key: `x-${string}`]: any; +} + +interface Deployment { + mode?: string; + endpoint_mode?: string; + replicas?: number | string; + labels?: ListOrDict; + rollback_config?: { + parallelism?: number | string; + delay?: string; + failure_action?: string; + monitor?: string; + max_failure_ratio?: number | string; + order?: 'start-first' | 'stop-first'; + [key: `x-${string}`]: any; + }; + update_config?: { + parallelism?: number | string; + delay?: string; + failure_action?: string; + monitor?: string; + max_failure_ratio?: number | string; + order?: 'start-first' | 'stop-first'; + [key: `x-${string}`]: any; + }; + resources?: { + limits?: { + cpus?: number | string; + memory?: string; + pids?: number | string; + [key: `x-${string}`]: any; + }; + reservations?: { + cpus?: number | string; + memory?: string; + generic_resources?: Array<{ + discrete_resource_spec?: { + kind?: string; + value?: number | string; + [key: `x-${string}`]: any; + }; + [key: `x-${string}`]: any; + }>; + devices?: Array<{ + capabilities?: string[]; + count?: string | number; + device_ids?: string[]; + driver?: string; + options?: ListOrDict; + [key: `x-${string}`]: any; + }>; + [key: `x-${string}`]: any; + }; + [key: `x-${string}`]: any; + }; + restart_policy?: { + condition?: string; + delay?: string; + max_attempts?: number | string; + window?: string; + [key: `x-${string}`]: any; + }; + placement?: { + constraints?: string[]; + preferences?: Array<{ + spread?: string; + [key: `x-${string}`]: any; + }>; + max_replicas_per_node?: number | string; + [key: `x-${string}`]: any; + }; + [key: `x-${string}`]: any; +} + +type Command = string | string[] | null; +type EnvFile = string | Array; +type StringOrList = string | string[]; +type ListOrDict = { [key: string]: string | number | boolean | null } | string[]; +type ExtraHosts = { [host: string]: string | string[] } | string[]; +interface BlkioLimit { path: string; rate: number | string; } +interface BlkioWeight { path: string; weight: number | string; } +type ServiceConfigOrSecret = string | { + source: string; + target?: string; + uid?: string; + gid?: string; + mode?: number | string; + [key: `x-${string}`]: any; +}; +type Ulimits = { [key: string]: number | string | { hard: number | string; soft: number | string } }; + +interface ServiceHook { + command?: Command; + user?: string; + privileged?: boolean | string; + working_dir?: string; + environment?: ListOrDict; + [key: `x-${string}`]: any; +} + +interface Network { + name?: string; + driver?: string; + driver_opts?: { [key: string]: string | number }; + ipam?: { + driver?: string; + config?: Array<{ + subnet?: string; + ip_range?: string; + gateway?: string; + aux_addresses?: { [key: string]: string }; + [key: `x-${string}`]: any; + }>; + options?: { [key: string]: string }; + [key: `x-${string}`]: any; + }; + external?: boolean | string | { name?: string;[key: `x-${string}`]: any }; + internal?: boolean | string; + enable_ipv4?: boolean | string; + enable_ipv6?: boolean | string; + attachable?: boolean | string; + labels?: ListOrDict; + [key: `x-${string}`]: any; +} + +interface Volume { + name?: string; + driver?: string; + driver_opts?: { [key: string]: string | number }; + external?: boolean | string | { name?: string;[key: `x-${string}`]: any }; + labels?: ListOrDict; + [key: `x-${string}`]: any; +} + +interface Secret { + name?: string; + environment?: string; + file?: string; + external?: boolean | string | { name?: string;[key: string]: any }; + labels?: ListOrDict; + driver?: string; + driver_opts?: { [key: string]: string | number }; + template_driver?: string; + [key: `x-${string}`]: any; +} + +interface Config { + name?: string; + content?: string; + environment?: string; + file?: string; + external?: boolean | string | { name?: string;[key: string]: any }; + labels?: ListOrDict; + template_driver?: string; + [key: `x-${string}`]: any; +} \ No newline at end of file diff --git a/src/typings/docker.ts b/src/typings/docker.ts new file mode 100644 index 00000000..522762c2 --- /dev/null +++ b/src/typings/docker.ts @@ -0,0 +1,34 @@ +interface DockerHost { + name: string; + url: string; + secure: boolean; +} + +interface ContainerInfo { + id: string; + hostId: string; + name: string; + image: string; + status: string; + state: string; + cpuUsage: number; + memoryUsage: number; +} + +interface HostStats { + hostId: string; + dockerVersion: string; + apiVersion: string; + os: string; + architecture: string; + totalMemory: number; + totalCPU: number; + labels: string[]; + containers: number; + containersRunning: number; + containersStopped: number; + containersPaused: number; + images: number; +} + +export type { HostStats, ContainerInfo, DockerHost }; diff --git a/src/typings/dockerCompose.ts b/src/typings/dockerCompose.ts deleted file mode 100644 index e30f7e0d..00000000 --- a/src/typings/dockerCompose.ts +++ /dev/null @@ -1,92 +0,0 @@ -export interface DockerComposeFile { - services: Record; - networks?: Record; - volumes?: Record; -} - -export interface ServiceDefinition { - image?: string; - build?: BuildDefinition; - container_name?: string; - command?: string | string[]; - environment?: Record; - ports?: string[] | PortMapping[]; - volumes?: string[]; - networks?: string[]; - restart?: string; - depends_on?: string[]; - deploy?: DeployDefinition; - env_file?: string[]; -} - -export interface BuildDefinition { - context: string; - dockerfile?: string; - args?: Record; - cache_from?: string[]; - labels?: Record; - target?: string; -} - -export interface PortMapping { - target: number; - published: number; - protocol?: "tcp" | "udp"; - mode?: "host" | "ingress"; -} - -export interface DeployDefinition { - replicas?: number; - resources?: ResourcesDefinition; - restart_policy?: RestartPolicyDefinition; - labels?: Record; - update_config?: UpdateConfigDefinition; -} - -export interface ResourcesDefinition { - limits?: ResourceLimits; - reservations?: ResourceReservations; -} - -export interface ResourceLimits { - cpus?: string; - memory?: string; -} - -export interface ResourceReservations { - cpus?: string; - memory?: string; -} - -export interface RestartPolicyDefinition { - condition?: "none" | "on-failure" | "any"; - delay?: string; - max_attempts?: number; - window?: string; -} - -export interface UpdateConfigDefinition { - parallelism?: number; - delay?: string; - failure_action?: "continue" | "pause"; - monitor?: string; - max_failure_ratio?: number; - order?: "start-first" | "stop-first"; -} - -export interface NetworkDefinition { - driver?: string; - driver_opts?: Record; - attachable?: boolean; - external?: boolean; - internal?: boolean; - labels?: Record; -} - -export interface VolumeDefinition { - driver?: string; - driver_opts?: Record; - external?: boolean; - labels?: Record; - name?: string; -} diff --git a/src/typings/dockerConfig.ts b/src/typings/dockerConfig.ts deleted file mode 100644 index a1749d1f..00000000 --- a/src/typings/dockerConfig.ts +++ /dev/null @@ -1,35 +0,0 @@ -interface target { - name: string; - url: string; - port: number; -} - -interface dockerConfig { - hosts: target[]; -} - -interface HostConfig { - name: string; - [key: string]: string | number; -} - -interface ContainerData { - name: string; - id: string; - hostName: string; - state: string; - cpu_usage: number; - mem_usage: number; - mem_limit: number; - net_rx: number; - net_tx: number; - current_net_rx: number; - current_net_tx: number; - networkMode: string; -} - -interface AllContainerData { - [hostName: string]: ContainerData[] | { error: string }; -} - -export { dockerConfig, target, ContainerData, AllContainerData, HostConfig }; diff --git a/src/typings/dockerStackEnv.ts b/src/typings/dockerStackEnv.ts deleted file mode 100644 index c784b85d..00000000 --- a/src/typings/dockerStackEnv.ts +++ /dev/null @@ -1,10 +0,0 @@ -interface dockerStackProperty { - name: string; - value: string; -} - -interface dockerStackEnv { - environment: dockerStackProperty[]; -} - -export { dockerStackEnv, dockerStackProperty }; diff --git a/src/typings/dockerode.ts b/src/typings/dockerode.ts new file mode 100644 index 00000000..a4604337 --- /dev/null +++ b/src/typings/dockerode.ts @@ -0,0 +1,162 @@ +interface DockerInfo { + ID: string; + Containers: number; + ContainersRunning: number; + ContainersPaused: number; + ContainersStopped: number; + Images: number; + Driver: string; + DriverStatus: [string, string][]; + DockerRootDir: string; + SystemStatus: [string, string][]; + Plugins: { + Volume: string[]; + Network: string[]; + Authorization: string[]; + Log: string[]; + }; + MemoryLimit: boolean; + SwapLimit: boolean; + KernelMemory: boolean; + CpuCfsPeriod: boolean; + CpuCfsQuota: boolean; + CPUShares: boolean; + CPUSet: boolean; + OomKillDisable: boolean; + IPv4Forwarding: boolean; + BridgeNfIptables: boolean; + BridgeNfIp6tables: boolean; + Debug: boolean; + NFd: number; + NGoroutines: number; + SystemTime: string; + LoggingDriver: string; + CgroupDriver: string; + NEventsListener: number; + KernelVersion: string; + OperatingSystem: string; + OSType: string; + Architecture: string; + NCPU: number; + MemTotal: number; + IndexServerAddress: string; + RegistryConfig: { + AllowNondistributableArtifactsCIDRs: string[]; + AllowNondistributableArtifactsHostnames: string[]; + InsecureRegistryCIDRs: string[]; + IndexConfigs: Record< + string, + { + Name: string; + Mirrors: string[]; + Secure: boolean; + Official: boolean; + } + >; + Mirrors: string[]; + }; + GenericResources: Array< + | { DiscreteResourceSpec: { Kind: string; Value: number } } + | { NamedResourceSpec: { Kind: string; Value: string } } + >; + HttpProxy: string; + HttpsProxy: string; + NoProxy: string; + Name: string; + Labels: string[]; + ExperimentalBuild: boolean; + ServerVersion: string; + ClusterStore: string; + ClusterAdvertise: string; + Runtimes: Record< + string, + { + path: string; + runtimeArgs?: string[]; + } + >; + DefaultRuntime: string; + Swarm: { + NodeID: string; + NodeAddr: string; + LocalNodeState: string; + ControlAvailable: boolean; + Error: string; + RemoteManagers: Array<{ + NodeID: string; + Addr: string; + }>; + Nodes: number; + Managers: number; + Cluster: { + ID: string; + Version: { + Index: number; + }; + CreatedAt: string; + UpdatedAt: string; + Spec: { + Name: string; + Labels: Record; + Orchestration: { + TaskHistoryRetentionLimit: number; + }; + Raft: { + SnapshotInterval: number; + KeepOldSnapshots: number; + LogEntriesForSlowFollowers: number; + ElectionTick: number; + HeartbeatTick: number; + }; + Dispatcher: { + HeartbeatPeriod: number; + }; + CAConfig: { + NodeCertExpiry: number; + ExternalCAs: Array<{ + Protocol: string; + URL: string; + Options: Record; + CACert: string; + }>; + SigningCACert: string; + SigningCAKey: string; + ForceRotate: number; + }; + EncryptionConfig: { + AutoLockManagers: boolean; + }; + TaskDefaults: { + LogDriver: { + Name: string; + Options: Record; + }; + }; + }; + TLSInfo: { + TrustRoot: string; + CertIssuerSubject: string; + CertIssuerPublicKey: string; + }; + RootRotationInProgress: boolean; + }; + }; + LiveRestoreEnabled: boolean; + Isolation: string; + InitBinary: string; + ContainerdCommit: { + ID: string; + Expected: string; + }; + RuncCommit: { + ID: string; + Expected: string; + }; + InitCommit: { + ID: string; + Expected: string; + }; + SecurityOptions: string[]; +} + +export type { DockerInfo }; diff --git a/src/typings/frontendConfig.ts b/src/typings/frontendConfig.ts deleted file mode 100644 index 6ce14979..00000000 --- a/src/typings/frontendConfig.ts +++ /dev/null @@ -1,12 +0,0 @@ -interface Container { - name: string; - hidden?: boolean; - tags?: string[]; - link?: string; - icon?: string; - pinned?: boolean; -} - -type FrontendConfig = Container[]; - -export { FrontendConfig }; diff --git a/src/typings/ha.ts b/src/typings/ha.ts deleted file mode 100644 index f0352fc0..00000000 --- a/src/typings/ha.ts +++ /dev/null @@ -1,20 +0,0 @@ -interface HighAvailabilityConfig { - active: boolean; - master: boolean; - nodes: string[]; -} - -interface Node { - ip: string; - port: number; -} - -interface HaNodeConfig { - master: string; -} - -interface NodeCache { - [nodes: string]: Node; -} - -export { HighAvailabilityConfig, Node, HaNodeConfig, NodeCache }; diff --git a/src/typings/hostData.ts b/src/typings/hostData.ts deleted file mode 100644 index cf5a78da..00000000 --- a/src/typings/hostData.ts +++ /dev/null @@ -1,26 +0,0 @@ -interface Component { - Name: string; - Version: string; -} - -interface JsonData { - hostName: string; - info: { - ID: string; - Containers: number; - ContainersRunning: number; - ContainersPaused: number; - ContainersStopped: number; - Images: number; - OperatingSystem: string; - KernelVersion: string; - Architecture: string; - MemTotal: number; - NCPU: number; - }; - version: { - Components: Component[]; - }; -} - -export { JsonData }; diff --git a/src/typings/plugin.ts b/src/typings/plugin.ts new file mode 100644 index 00000000..9994ea67 --- /dev/null +++ b/src/typings/plugin.ts @@ -0,0 +1,25 @@ +import { ContainerInfo } from "~/typings/docker"; +import { HostStats } from "~/typings/docker"; + +interface Plugin { + name: string; + + // Container lifecycle hooks + onContainerStart?: (containerInfo: ContainerInfo) => void; + onContainerStop?: (containerInfo: ContainerInfo) => void; + onContainerExit?: (containerInfo: ContainerInfo) => void; + onContainerCreate?: (containerInfo: ContainerInfo) => void; + onContainerDestroy?: (containerInfo: ContainerInfo) => void; + onContainerPause?: (containerInfo: ContainerInfo) => void; + onContainerUnpause?: (containerInfo: ContainerInfo) => void; + onContainerRestart?: (containerInfo: ContainerInfo) => void; + onContainerUpdate?: (containerInfo: ContainerInfo) => void; + onContainerRename?: (containerInfo: ContainerInfo) => void; + onContainerHealthStatus?: (containerInfo: ContainerInfo) => void; + + // Host lifecycle hooks + onHostUnreachable?: (HostStats: HostStats) => void; + onHostReachableAgain?: (HostStats: HostStats) => void; +} + +export type { Plugin }; diff --git a/src/typings/response.ts b/src/typings/response.ts deleted file mode 100644 index b122dfe2..00000000 --- a/src/typings/response.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface StatusResponse { - ApiReachable: boolean; - online: { [key: string]: boolean }; -} - -export { StatusResponse }; diff --git a/src/typings/stackConfig.ts b/src/typings/stackConfig.ts deleted file mode 100644 index 45c72553..00000000 --- a/src/typings/stackConfig.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface stackConfig { - stacks: string[]; -} - -export { stackConfig }; diff --git a/src/typings/states.ts b/src/typings/states.ts deleted file mode 100644 index d5eed20b..00000000 --- a/src/typings/states.ts +++ /dev/null @@ -1,10 +0,0 @@ -interface Container { - name: string; - id: string; - state: string; - hostName: string; -} - -type ContainerStates = Container[]; - -export { ContainerStates, Container }; diff --git a/src/typings/syncRequestBody.ts b/src/typings/syncRequestBody.ts deleted file mode 100644 index 36fd70a4..00000000 --- a/src/typings/syncRequestBody.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface SyncRequestBody { - files: Record; -} - -export { SyncRequestBody }; diff --git a/src/typings/table.ts b/src/typings/table.ts deleted file mode 100644 index cf0c18ab..00000000 --- a/src/typings/table.ts +++ /dev/null @@ -1,11 +0,0 @@ -type Table = { - id: number; // Primary key, auto-incremented - info: string; // Non-null text field - timestamp: string; // ISO 8601 formatted datetime string -}; - -interface DataRow { - info: string; -} - -export { Table, DataRow }; diff --git a/src/typings/template.ts b/src/typings/template.ts deleted file mode 100644 index 71e0c8a3..00000000 --- a/src/typings/template.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface TemplateData { - text: string; -} - -export { TemplateData }; diff --git a/src/typings/websocket.ts b/src/typings/websocket.ts new file mode 100644 index 00000000..a9712473 --- /dev/null +++ b/src/typings/websocket.ts @@ -0,0 +1,9 @@ +import type { Readable } from "stream"; +import type internal from "stream"; + +interface streams { + statsStream: Readable; + splitStream: internal.Transform; +} + +export { streams }; diff --git a/src/utils/assets/api-icon.svg b/src/utils/assets/api-icon.svg deleted file mode 100644 index 5a4fdb7c..00000000 --- a/src/utils/assets/api-icon.svg +++ /dev/null @@ -1 +0,0 @@ -\ diff --git a/src/utils/assets/container-icon.svg b/src/utils/assets/container-icon.svg deleted file mode 100644 index 15ed98c6..00000000 --- a/src/utils/assets/container-icon.svg +++ /dev/null @@ -1 +0,0 @@ -\ diff --git a/src/utils/assets/server-icon.svg b/src/utils/assets/server-icon.svg deleted file mode 100644 index 31c92d4a..00000000 --- a/src/utils/assets/server-icon.svg +++ /dev/null @@ -1 +0,0 @@ -\ diff --git a/src/utils/atomicWrite.ts b/src/utils/atomicWrite.ts deleted file mode 100644 index d279475e..00000000 --- a/src/utils/atomicWrite.ts +++ /dev/null @@ -1,35 +0,0 @@ -import fs from "fs"; -import logger from "./logger"; -import { AtomicWriteOptions } from "../typings/atomicWrite"; - -export function atomicWrite( - targetPath: string, - data: object | string | Buffer | Record, - options: AtomicWriteOptions = {}, -): void { - const { mode = 0o600, exclusive = false } = options; - const tempFile = `${targetPath}.tmp`; - - try { - const writeData = - typeof data === "object" && !(data instanceof Buffer) - ? JSON.stringify(data, null, 2) - : data; - - if (exclusive && fs.existsSync(targetPath)) { - throw new Error(`File already exists: ${targetPath}`); - } - - fs.writeFileSync(tempFile, writeData, { mode }); - - fs.renameSync(tempFile, targetPath); - - logger.debug(`File successfully written to: ${targetPath}`); - } catch (error: unknown) { - if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile); - logger.error( - `Failed to write file at ${targetPath}: ${(error as Error).message}`, - ); - throw error; - } -} diff --git a/src/utils/connectionChecker.ts b/src/utils/connectionChecker.ts deleted file mode 100644 index 5a45505b..00000000 --- a/src/utils/connectionChecker.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as fs from "fs"; -import * as net from "net"; -import logger from "./logger"; -import { target } from "../typings/dockerConfig"; -import { StatusResponse } from "../typings/response"; - -const filePath: string = "./src/data/dockerConfig.json"; - -async function checkHostStatus(hosts: target[]): Promise { - const results: { [key: string]: boolean } = {}; - for (const host of hosts) { - const { name, url, port } = host; - - const isOnline = await checkPort(url, port); - - results[name] = !!isOnline; - - if (results[name] == true) { - logger.debug(`${host.url}:${port} is online`); - } else { - logger.debug(`${host.url}:${port} is unreachable`); - } - } - - return { - ApiReachable: true, - online: results, - }; -} - -function checkPort(host: string, port: number): Promise { - return new Promise((resolve) => { - const socket = new net.Socket(); - socket.setTimeout(3000); - - socket.on("connect", () => { - socket.end(); - resolve(true); - }); - - socket.on("timeout", () => { - socket.destroy(); - resolve(false); - }); - - socket.on("error", () => { - socket.destroy(); - resolve(false); - }); - - socket.connect(port, host); - }); -} - -async function checkReachability(): Promise { - try { - const data = fs.readFileSync(filePath, "utf-8"); - const parsedData = JSON.parse(data); - const hosts: target[] = parsedData.hosts; - return await checkHostStatus(hosts); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -export default checkReachability; diff --git a/src/utils/containerService.ts b/src/utils/containerService.ts deleted file mode 100644 index 0bb0a4e7..00000000 --- a/src/utils/containerService.ts +++ /dev/null @@ -1,173 +0,0 @@ -import logger from "./logger"; -import { ContainerInfo } from "dockerode"; -import { getDockerClient } from "./dockerClient"; -import fs from "fs"; -import { atomicWrite } from "./atomicWrite"; -const configPath = "./src/data/dockerConfig.json"; -import { AllContainerData, HostConfig } from "../typings/dockerConfig"; -import { generateGraphJSON } from "../handlers/graph"; -import { WebSocket } from "ws"; - -export function loadConfig() { - try { - if (!fs.existsSync(configPath)) { - logger.warn( - `Config file not found. Creating an empty file at ${configPath}`, - ); - atomicWrite(configPath, JSON.stringify({ hosts: [] }, null, 2)); - } - - const configData = fs.readFileSync(configPath, "utf-8"); - logger.debug("Loaded " + configPath); - return JSON.parse(configData); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return { hosts: [] }; - } -} - -export async function fetchContainersForHost(hostName: string) { - const config = loadConfig(); - const hostConfig = config.hosts.find((h: HostConfig) => h.name === hostName); - - if (!hostConfig) { - throw new Error(`Host ${hostName} not found in configuration`); - } - - try { - const docker = getDockerClient(hostName); - const containers: ContainerInfo[] = await docker.listContainers({ - all: true, - }); - - return await Promise.all( - containers.map(async (container) => { - try { - const containerInstance = docker.getContainer(container.Id); - const [containerInfo, containerStats] = await Promise.all([ - containerInstance.inspect(), - containerInstance.stats({ stream: false }), - ]); - - const cpuDelta = - containerStats.cpu_stats.cpu_usage.total_usage - - containerStats.precpu_stats.cpu_usage.total_usage; - const systemCpuDelta = - containerStats.cpu_stats.system_cpu_usage - - containerStats.precpu_stats.system_cpu_usage; - const cpuUsage = - systemCpuDelta > 0 - ? (cpuDelta / systemCpuDelta) * - containerStats.cpu_stats.online_cpus - : 0; - - return { - name: container.Names[0].replace("/", ""), - id: container.Id, - hostName, - state: container.State, - cpu_usage: cpuUsage, - mem_usage: containerStats.memory_stats.usage, - mem_limit: containerStats.memory_stats.limit, - net_rx: containerStats.networks?.eth0?.rx_bytes || 0, - net_tx: containerStats.networks?.eth0?.tx_bytes || 0, - current_net_rx: containerStats.networks?.eth0?.rx_bytes || 0, - current_net_tx: containerStats.networks?.eth0?.tx_bytes || 0, - networkMode: containerInfo.HostConfig.NetworkMode || "unknown", - }; - } catch (error) { - logger.error(`Error processing container ${container.Id}: ${error}`); - return { - name: container.Names[0].replace("/", ""), - id: container.Id, - hostName, - state: container.State, - cpu_usage: 0, - mem_usage: 0, - mem_limit: 0, - net_rx: 0, - net_tx: 0, - current_net_rx: 0, - current_net_tx: 0, - networkMode: "unknown", - }; - } - }), - ); - } catch (error) { - logger.error(`Error fetching containers for ${hostName}: ${error}`); - throw error; - } -} - -export async function fetchAllContainers(): Promise { - const config = loadConfig(); - const allContainerData: AllContainerData = {}; - - await Promise.all( - config.hosts.map(async (hostConfig: HostConfig) => { - try { - allContainerData[hostConfig.name] = await fetchContainersForHost( - hostConfig.name, - ); - } catch (error) { - allContainerData[hostConfig.name] = { - error: `Error fetching containers: ${error instanceof Error ? error.message : String(error)}`, - }; - } - }), - ); - - generateGraphJSON(allContainerData); - return allContainerData; -} - -export async function streamContainerData(ws: WebSocket, hostName: string) { - try { - const containers = await fetchContainersForHost(hostName); - ws.send(JSON.stringify({ type: "containers", data: containers })); - - const docker = getDockerClient(hostName); - const eventStream = await docker.getEvents(); - - // eslint-disable-next-line - if (!(eventStream instanceof require("stream").Readable)) { - throw new Error("Failed to get valid event stream"); - } - - const handleData = (chunk: Buffer) => { - ws.send( - JSON.stringify({ type: "container-event", data: chunk.toString() }), - ); - }; - - const handleError = (err: Error) => { - logger.error(`Event stream error for ${hostName}: ${err.message}`); - ws.close(); - }; - - eventStream.on("data", handleData).on("error", handleError); - - const closeHandler = () => { - eventStream - .removeListener("data", handleData) - .removeListener("error", handleError) - .removeListener("closed", handleError); - logger.info(`Closed event stream for ${hostName}`); - }; - - ws.on("close", closeHandler); - ws.on("error", closeHandler); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - logger.error("Container data error:", message); - ws.send( - JSON.stringify({ - error: "Failed to fetch container data", - details: message, - }), - ); - ws.close(); - } -} diff --git a/src/utils/dockerClient.ts b/src/utils/dockerClient.ts deleted file mode 100644 index ff770888..00000000 --- a/src/utils/dockerClient.ts +++ /dev/null @@ -1,41 +0,0 @@ -import Docker from "dockerode"; -import fs from "fs"; -import logger from "./logger"; -import { dockerConfig, target } from "../typings/dockerConfig"; - -function loadDockerConfig(): dockerConfig { - const configPath = "./src/data/dockerConfig.json"; - try { - const rawData = fs.readFileSync(configPath, "utf-8"); - logger.debug("Refreshed DockerConfig.json"); - return JSON.parse(rawData) as dockerConfig; - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - throw new Error(errorMsg); - } -} - -function createDockerClient(hostConfig: target): Docker { - logger.info( - `Creating Docker client for host: ${hostConfig.url} on port: ${hostConfig.port || 2375}`, - ); - return new Docker({ - host: hostConfig.url, - port: hostConfig.port || 2375, - protocol: "http", - }); -} - -export const getDockerClient = (hostName: string): Docker => { - logger.debug(`Getting Docker Client for ${hostName}`); - const config = loadDockerConfig(); - const hostConfig = config.hosts.find((host) => host.name === hostName); - - if (!hostConfig) { - const errorMsg = `Docker host ${hostName} not found in configuration`; - logger.error(errorMsg); - throw new Error(errorMsg); - } - return createDockerClient(hostConfig); -}; diff --git a/src/utils/extractHostData.ts b/src/utils/extractHostData.ts deleted file mode 100644 index 992f9638..00000000 --- a/src/utils/extractHostData.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { JsonData } from "../typings/hostData"; -import logger from "./logger"; - -type ComponentMap = Record; - -interface RelevantData { - hostName: string; - info: { - ID: string; - Containers: number; - ContainersRunning: number; - ContainersPaused: number; - ContainersStopped: number; - Images: number; - OperatingSystem: string; - KernelVersion: string; - Architecture: string; - MemTotal: number; - NCPU: number; - }; - version: { - Components: ComponentMap; - }; -} - -function processComponents(components: unknown): ComponentMap { - try { - if (!Array.isArray(components)) return {}; - - return components.reduce((acc, component) => { - if ( - typeof component === "object" && - component !== null && - "Name" in component && - "Version" in component - ) { - const { Name, Version } = component; - if (typeof Name === "string" && typeof Version === "string") { - acc[Name] = Version; - } - } - return acc; - }, {}); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - logger.error(`Error processing components: ${errorMessage}`); - return {}; - } -} - -export function extractRelevantData(jsonData: JsonData): RelevantData { - return { - hostName: jsonData.hostName, - info: { - ID: jsonData.info.ID, - Containers: jsonData.info.Containers, - ContainersRunning: jsonData.info.ContainersRunning, - ContainersPaused: jsonData.info.ContainersPaused, - ContainersStopped: jsonData.info.ContainersStopped, - Images: jsonData.info.Images, - OperatingSystem: jsonData.info.OperatingSystem, - KernelVersion: jsonData.info.KernelVersion, - Architecture: jsonData.info.Architecture, - MemTotal: jsonData.info.MemTotal, - NCPU: jsonData.info.NCPU, - }, - version: { - Components: processComponents(jsonData?.version?.Components), - }, - }; -} - -export default extractRelevantData; diff --git a/src/utils/logger.ts b/src/utils/logger.ts deleted file mode 100644 index 2fd67bd5..00000000 --- a/src/utils/logger.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { createLogger, format, transports } from "winston"; -import DailyRotateFile from "winston-daily-rotate-file"; -import { LOG_LEVEL } from "../config/variables"; - -const colors = { - gray: "\x1b[90m", - reset: "\x1b[0m", - white: "\x1b[97m", - red: "\x1b[31m", - green: "\x1b[32m", - yellow: "\x1b[33m", - blue: "\x1b[34m", -}; - -function colorizeLogLevel(level: string, levelName: string) { - switch (level) { - case "info": - return `${colors.green}${levelName}${colors.reset}`; - case "debug": - return `${colors.blue}${levelName}${colors.reset}`; - case "error": - return `${colors.red}${levelName}${colors.reset}`; - case "warn": - return `${colors.yellow}${levelName}${colors.reset}`; - default: - return `${colors.gray}UNKNOWN${colors.reset}`; - } -} - -// Filter out Exit listeners logs -const filterLogs = format((info) => { - if ( - typeof info.message === "string" && - info.message.includes("Exit listeners detected") - ) { - return false; - } - return info; -}); - -const logger = createLogger({ - level: LOG_LEVEL, - format: format.combine( - filterLogs(), - format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), - ), - transports: [ - new transports.Console({ - format: format.combine( - format.printf((info) => { - const level = info.level.toUpperCase().padEnd(5, " "); - const timestamp = `${colors.gray}${info.timestamp}${colors.reset}`; - const levelColorized = colorizeLogLevel( - info.level.toLowerCase(), - level, - ); - const message = `${colors.white}${(info.message as string).replace(/\n|\r/g, "")}${colors.reset}`; - - return `${timestamp} ${levelColorized} : ${message}`; - }), - ), - }), - new DailyRotateFile({ - filename: "logs/app-%DATE%.log", - datePattern: "YYYY-MM-DD", - maxSize: "20m", - maxFiles: "14d", - zippedArchive: true, - format: format.combine( - format.printf((info) => { - const level = info.level.toUpperCase().padEnd(5, " "); - return `${info.timestamp} ${level} : ${info.message}`; - }), - ), - }), - ], -}); - -export default logger; diff --git a/src/utils/notifications/_notify.ts b/src/utils/notifications/_notify.ts deleted file mode 100644 index 49717f90..00000000 --- a/src/utils/notifications/_notify.ts +++ /dev/null @@ -1,51 +0,0 @@ -import logger from "../../utils/logger"; -import { telegramNotification } from "./telegram"; -import { slackNotification } from "./slack"; -import { discordNotification } from "./discord"; -import { emailNotification } from "./email"; -import { whatsappNotification } from "./whatsapp"; -import { pushbulletNotification } from "./pushbullet"; -import { pushoverNotification } from "./pushover"; - -async function notify(type: string, containerId: string) { - if (!containerId) { - logger.error("Container ID is required."); - throw new Error("Container ID is required."); - } - - switch (type) { - case "telegram": - logger.debug("Sending Telegram notification..."); - await telegramNotification(containerId); - break; - case "slack": - logger.debug("Sending Slack notification..."); - await slackNotification(containerId); - break; - case "discord": - logger.debug("Sending Discord notification..."); - await discordNotification(containerId); - break; - case "email": - logger.debug("Sending Email notification..."); - await emailNotification(containerId); - break; - case "whatsapp": - logger.debug("Sending WhatsApp notification..."); - await whatsappNotification(containerId); - break; - case "pushbullet": - logger.debug("Sending Pushbullet notification..."); - await pushbulletNotification(containerId); - break; - case "pushover": - logger.debug("Sending Pushover notification..."); - await pushoverNotification(containerId); - break; - default: - logger.error("Unknown notification type."); - throw new Error("Unknown notification type."); - } -} - -export default notify; diff --git a/src/utils/notifications/_template.ts b/src/utils/notifications/_template.ts deleted file mode 100644 index fd5d71ed..00000000 --- a/src/utils/notifications/_template.ts +++ /dev/null @@ -1,76 +0,0 @@ -import fs from "fs"; -import logger from "../logger"; -import { ContainerStates, Container } from "../../typings/states"; - -const templatePath: string = "./src/data/template.json"; -const containersPath: string = "./src/data/states.json"; - -interface Template { - text: string; -} - -function getTemplate(): Template | null { - try { - const data = fs.readFileSync(templatePath, "utf8"); - return JSON.parse(data); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return null; - } -} - -function setTemplate(newTemplate: string): void { - try { - fs.writeFileSync( - templatePath, - JSON.stringify({ text: newTemplate }, null, 2), - "utf8", - ); - logger.debug("Template updated successfully"); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} - -function renderTemplate(containerId: string): string | null { - const template = getTemplate(); - if (!template) { - logger.error("Template is missing or not a string"); - return null; - } - - try { - const data = fs.readFileSync(containersPath, "utf8"); - const containers = JSON.parse(data); - - let containerData: ContainerStates | null = null; - for (const host in containers) { - containerData = containers[host].find( - (c: Container) => c.id === containerId, - ); - if (containerData) { - break; - } - } - - if (!containerData) { - logger.error(`Container with ID ${containerId} not found`); - return null; - } - - // Substitute placeholders in the template with container data - return Object.keys(containerData).reduce((text, key) => { - const value = containerData[key as keyof ContainerStates]; - // Convert value to a string to avoid errors - return text.replace(new RegExp(`{{${key}}}`, "g"), String(value)); - }, template.text); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - return null; - } -} - -export { getTemplate, setTemplate, renderTemplate }; diff --git a/src/utils/notifications/discord.ts b/src/utils/notifications/discord.ts deleted file mode 100644 index d9be3a02..00000000 --- a/src/utils/notifications/discord.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { DISCORD_WEBHOOK_URL } from "../../config/variables"; - -const discord_webhook_url: string = DISCORD_WEBHOOK_URL; - -export async function discordNotification(containerId: string): Promise { - const discord_message: string | null = renderTemplate(containerId); - if (!discord_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!discord_webhook_url) { - logger.error("Discord webhook URL is not set."); - return; - } - - const postData = JSON.stringify({ - content: discord_message, - }); - - const url = new URL(discord_webhook_url); - - const options = { - hostname: url.hostname, - path: url.pathname, - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`Discord API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending Discord message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/notifications/email.ts b/src/utils/notifications/email.ts deleted file mode 100644 index 62b37d3a..00000000 --- a/src/utils/notifications/email.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { SendMailOptions, createTransport } from "nodemailer"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { - EMAIL_SENDER, - EMAIL_SERVICE, - EMAIL_PASSWORD, - EMAIL_RECIPIENT, -} from "../../config/variables"; - -const email_sender: string = EMAIL_SENDER; -const email_recipient: string = EMAIL_RECIPIENT; -const email_password: string = EMAIL_PASSWORD; -const email_service: string = EMAIL_SERVICE; - -export async function emailNotification(containerId: string) { - // Validate email configuration parameters - if (!email_sender || !email_recipient || !email_password || !email_service) { - logger.error( - "Email notification failed: Missing configuration parameters. " + - "Please ensure EMAIL_SENDER, EMAIL_RECIPIENT, EMAIL_PASSWORD, and EMAIL_SERVICE are set in environment variables.", - ); - return; - } - - const email_message: string | null = renderTemplate(containerId); - if (!email_message) { - logger.error("Failed to create notification message."); - return; - } - - const transporter = createTransport({ - service: email_service, - auth: { - user: email_sender, - pass: email_password, - }, - }); - - const mailOptions: SendMailOptions = { - from: email_sender, - to: email_recipient, - subject: "DockStat", - text: email_message, - }; - - try { - await transporter.sendMail(mailOptions); - } catch (error: unknown) { - const errorMsg = error instanceof Error ? error.message : String(error); - logger.error(errorMsg); - } -} diff --git a/src/utils/notifications/pushbullet.ts b/src/utils/notifications/pushbullet.ts deleted file mode 100644 index 811427a1..00000000 --- a/src/utils/notifications/pushbullet.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { PUSHBULLET_ACCESS_TOKEN } from "../../config/variables"; - -const pushbullet_access_token: string = PUSHBULLET_ACCESS_TOKEN; - -export async function pushbulletNotification( - containerId: string, -): Promise { - const pushbullet_message: string | null = renderTemplate(containerId); - if (!pushbullet_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!pushbullet_access_token) { - logger.error("Pushbullet access token is not set."); - return; - } - - const postData = JSON.stringify({ - type: "note", - title: "Container Notification", - body: pushbullet_message, - }); - - const options = { - hostname: "api.pushbullet.com", - path: "/v2/pushes", - method: "POST", - headers: { - "Access-Token": pushbullet_access_token, - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`Pushbullet API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending Pushbullet message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/notifications/pushover.ts b/src/utils/notifications/pushover.ts deleted file mode 100644 index aac71b3b..00000000 --- a/src/utils/notifications/pushover.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { PUSHOVER_USER_KEY, PUSHOVER_API_TOKEN } from "../../config/variables"; - -const pushover_user_key: string = PUSHOVER_USER_KEY; -const pushover_api_token: string = PUSHOVER_API_TOKEN; - -export async function pushoverNotification(containerId: string): Promise { - const pushover_message: string | null = renderTemplate(containerId); - if (!pushover_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!pushover_api_token || !pushover_user_key) { - logger.error("Pushover API token or user key is not set."); - return; - } - - const postData = new URLSearchParams({ - token: pushover_api_token, - user: pushover_user_key, - message: pushover_message, - }).toString(); - - const options = { - hostname: "api.pushover.net", - path: "/1/messages.json", - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`Pushover API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending Pushover message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/notifications/slack.ts b/src/utils/notifications/slack.ts deleted file mode 100644 index e1e7216b..00000000 --- a/src/utils/notifications/slack.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { SLACK_WEBHOOK_URL } from "../../config/variables"; - -const slack_webhook_url: string = SLACK_WEBHOOK_URL; - -export async function slackNotification(containerId: string): Promise { - const slack_message: string | null = renderTemplate(containerId); - if (!slack_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!slack_webhook_url) { - logger.error("Slack webhook URL is not set."); - return; - } - - const postData = JSON.stringify({ - text: slack_message, - }); - - const url = new URL(slack_webhook_url); - - const options = { - hostname: url.hostname, - path: url.pathname, - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`Slack API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending Slack message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/notifications/telegram.ts b/src/utils/notifications/telegram.ts deleted file mode 100644 index 440e0916..00000000 --- a/src/utils/notifications/telegram.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID } from "../../config/variables"; - -const telegram_bot_token: string = TELEGRAM_BOT_TOKEN; -const telegram_chat_id: string = TELEGRAM_CHAT_ID; - -export async function telegramNotification(containerId: string): Promise { - const telegram_message: string | null = renderTemplate(containerId); - if (!telegram_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!telegram_bot_token || !telegram_chat_id) { - logger.error("Telegram bot token or chat ID is not set."); - return; - } - - const postData = JSON.stringify({ - chat_id: telegram_chat_id, - text: telegram_message, - }); - - const options = { - hostname: "api.telegram.org", - path: `/bot${telegram_bot_token}/sendMessage`, - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`Telegram API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/notifications/whatsapp.ts b/src/utils/notifications/whatsapp.ts deleted file mode 100644 index 1eb7575e..00000000 --- a/src/utils/notifications/whatsapp.ts +++ /dev/null @@ -1,58 +0,0 @@ -import * as https from "https"; -import logger from "../logger"; -import { renderTemplate } from "./_template"; -import { WHATSAPP_API_URL, WHATSAPP_RECIPIENT } from "../../config/variables"; - -const whatsapp_api_url: string = WHATSAPP_API_URL; -const whatsapp_recipient: string = WHATSAPP_RECIPIENT; - -export async function whatsappNotification(containerId: string): Promise { - const whatsapp_message: string | null = renderTemplate(containerId); - if (!whatsapp_message) { - logger.error("Failed to create notification message."); - return; - } - - if (!whatsapp_api_url || !whatsapp_recipient) { - logger.error("WhatsApp API URL or recipient is not set."); - return; - } - - const postData = JSON.stringify({ - to: whatsapp_recipient, - body: whatsapp_message, - }); - - const url = new URL(whatsapp_api_url); - - const options = { - hostname: url.hostname, - path: url.pathname, - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(postData), - }, - }; - - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - if (res.statusCode !== 200) { - logger.error(`WhatsApp API error: ${data}`); - } - }); - }); - - req.on("error", (error) => { - logger.error("Error sending WhatsApp message:", error); - }); - - req.write(postData); - req.end(); -} diff --git a/src/utils/rateLimitFS.ts b/src/utils/rateLimitFS.ts deleted file mode 100644 index a8f0b42d..00000000 --- a/src/utils/rateLimitFS.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { promises as fs, existsSync } from "fs"; - -const delay = (ms: number): Promise => - new Promise((resolve) => setTimeout(resolve, ms)); - -let lastOperationTime = 0; -const rateLimitDuration = 500; - -export const rateLimitedReadFile = async ( - filePath: string, - encoding: BufferEncoding = "utf8", -): Promise => { - const now = Date.now(); - const timeSinceLastOperation = now - lastOperationTime; - - if (timeSinceLastOperation < rateLimitDuration) { - await delay(rateLimitDuration - timeSinceLastOperation); - } - - lastOperationTime = Date.now(); - return fs.readFile(filePath, encoding); -}; - -export const rateLimitedExistsSync = async ( - filePath: string, -): Promise => { - const now = Date.now(); - const timeSinceLastOperation = now - lastOperationTime; - - if (timeSinceLastOperation < rateLimitDuration) { - await delay(rateLimitDuration - timeSinceLastOperation); - } - - lastOperationTime = Date.now(); - return existsSync(filePath); -}; diff --git a/src/utils/startServer.ts b/src/utils/startServer.ts deleted file mode 100644 index 52dcc256..00000000 --- a/src/utils/startServer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Express } from "express"; -import { Server } from "http"; -import { startMasterNode } from "../controllers/highAvailability"; -import writeUserConf from "../config/hostsystem"; -import initFiles from "../config/initFiles"; - -export function startServer(app: Express, server: Server, port: number) { - if (process.env.NODE_ENV === "testing") { - writeUserConf(port); - initFiles(); - } - - server.listen(port, () => { - startMasterNode(); - }); -} diff --git a/src/utils/swaggerDocs.ts b/src/utils/swaggerDocs.ts deleted file mode 100644 index 7ed90d9d..00000000 --- a/src/utils/swaggerDocs.ts +++ /dev/null @@ -1,12 +0,0 @@ -import swaggerUi from "swagger-ui-express"; -import { options } from "../config/swaggerConfig"; -import yaml from "yamljs"; -import express from "express"; -import { SwaggerDefinition } from "swagger-jsdoc"; - -const swaggerDocs = (app: express.Application) => { - const swaggerYaml: SwaggerDefinition = yaml.load("./src/config/swagger.yaml"); - app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerYaml, options)); -}; - -export default swaggerDocs; diff --git a/src/utils/webSocket.ts b/src/utils/webSocket.ts deleted file mode 100644 index 66d1f74b..00000000 --- a/src/utils/webSocket.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Server } from "http"; -import { WebSocketServer, WebSocket } from "ws"; -import { URL } from "url"; -import fs from "fs"; -import logger from "./logger"; -import { streamContainerData } from "./containerService"; - -export function setupWebSocket(server: Server) { - const wss = new WebSocketServer({ noServer: true }); - - server.on("upgrade", (req, socket, head) => { - logger.debug(`Received upgrade request for URL: ${req.url}`); - const baseURL = `http://${req.headers.host}/`; - const requestURL = new URL(req.url || "", baseURL); - const { pathname } = requestURL; - logger.debug(`Parsed pathname: ${pathname}`); - - // Debug log to verify path handling - logger.debug(`Handling upgrade for path: ${pathname}`); - - if (pathname === "/wss/container-data" || pathname === "/wss/server-logs") { - wss.handleUpgrade(req, socket, head, (ws) => { - wss.emit("connection", ws, req); - }); - } else { - logger.warn(`Rejected WebSocket connection to invalid path: ${pathname}`); - socket.write("HTTP/1.1 404 Not Found\r\n\r\n"); - socket.destroy(); - } - }); - - server.on("error", (error) => { - logger.error("HTTP server error:", error); - }); - - logger.debug("WebSocket server attached to HTTP server"); - - wss.on("connection", (ws: WebSocket, req) => { - const baseURL = `http://${req.headers.host}/`; - const requestURL = new URL(req.url || "", baseURL); - const { pathname } = requestURL; - - logger.info(`WebSocket connection established to ${pathname}`); - - const handleError = (error: string) => { - ws.send(JSON.stringify({ error })); - ws.close(); - }; - - if (pathname === "/wss/container-data") { - const hostName = requestURL.searchParams.get("host"); - if (!hostName) { - handleError("Missing required host parameter"); - return; - } - streamContainerData(ws, hostName); - } else if (pathname === "/wss/server-logs") { - const logFiles = fs - .readdirSync("logs/") - .filter((file) => file.startsWith("app-")); - - if (logFiles.length === 0) { - console.error("No log files found"); - return; - } - - const sortedLogFiles = logFiles.sort((a, b) => { - const dateA = a.match(/\d{4}-\d{2}-\d{2}/)?.[0] ?? ""; - const dateB = b.match(/\d{4}-\d{2}-\d{2}/)?.[0] ?? ""; - - return dateB.localeCompare(dateA); - }); - - const logPath = "logs/" + sortedLogFiles[0]; - - if (!fs.existsSync(logPath)) { - handleError("Log file not found"); - logger.error(`Log file ${logPath} not found`); - return; - } - - // Read the initial content of the log file - const history = fs.readFileSync(logPath, "utf-8"); - ws.send(JSON.stringify({ type: "log-history", data: history })); - - // Watch the log file for changes - const watcher = fs.watchFile( - logPath, - { interval: 1000 }, - (curr, prev) => { - if (curr.size > prev.size) { - const stream = fs.createReadStream(logPath, { - start: prev.size, - end: curr.size - 1, - encoding: "utf-8", - }); - - stream.on("data", (chunk) => { - ws.send(JSON.stringify({ type: "log-update", data: chunk })); - }); - } - }, - ); - - ws.on("close", () => { - watcher.removeAllListeners(); - logger.info("Closed WebSocket connection for logs"); - }); - } else { - handleError("Invalid WebSocket endpoint"); - } - }); -} diff --git a/tsconfig.json b/tsconfig.json index c4f6f4c0..ab566ad1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,107 @@ { "compilerOptions": { - "resolveJsonModule": true, - "target": "ES2020", - "outDir": "dist/src", - "module": "CommonJS", - "moduleResolution": "node", - "strict": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "esModuleInterop": true - }, - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Recommended", - "include": ["src/**/*", "**/*.d.ts", "__tests__/**/*"], - "exclude": ["node_modules", "**/*.spec.ts"] + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ES2022" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "~/*": ["./src/*"] + } /* Specify a set of entries that re-map imports to additional lookup locations. */, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "bun-types" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + "resolveJsonModule": true /* Enable importing .json files. */, + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } }