diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 447aaa1..cd68a23 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -4,3 +4,10 @@ paths: - '"inputs" section is alias node but mapping node is expected' - '"paths" section must be sequence node but got alias node with "" tag' - '"paths-ignore" section must be sequence node but got alias node with "" tag' + .github/workflows/issue.yaml: + ignore: + - 'missing input "app-id" which is required by action "actions/create-github-app-token@v3"' + - 'input "client-id" is not defined in action "actions/create-github-app-token@v3"' + .github/workflows/test.yaml: + ignore: + - 'property ".+" is not defined in object type' diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a8fd980..d1c7def 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -14,13 +14,13 @@ on: # types: [published] env: - dev: ${{ inputs.dev || github.event.release.prerelease }} + dev: ${{ (inputs.dev || github.event.release.prerelease) && 'dev' || '' }} jobs: build: name: "Build" runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 15 permissions: contents: write @@ -61,11 +61,11 @@ jobs: platforms: linux/amd64,linux/arm64 - name: "Update Version Tags" - if: ${{ !env.dev }} id: version uses: cssnr/update-version-tags-action@v2 with: prefix: "" + dry_run: true tags: | ${{ inputs.tags }} @@ -73,7 +73,7 @@ jobs: continue-on-error: true run: | echo "github.ref_name: ${{ github.ref_name }}" - echo "tags1: ${{ env.dev && 'dev' || '' }}" + echo "tags1: ${{ env.dev }}" echo "tags2: ${{ steps.version.outputs.tags }}" echo "tags3: ${{ inputs.tags }}" @@ -83,7 +83,7 @@ jobs: with: images: "ghcr.io/${{ github.repository }}" tags: | - ${{ env.dev && 'dev' || '' }} + ${{ env.dev }} ${{ steps.version.outputs.tags }} ${{ inputs.tags }} @@ -114,3 +114,4 @@ jobs: uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1.16.0 with: webhook: ${{ secrets.DISCORD_WEBHOOK }} + description: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 6f4a8ac..606a457 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -2,11 +2,13 @@ name: "Deploy" on: workflow_call: - workflow_dispatch: - inputs: + inputs: &inputs version: description: "Version Tag" required: false + type: string + workflow_dispatch: + inputs: *inputs #workflow_run: # workflows: ["Build"] # types: [completed] @@ -29,12 +31,23 @@ jobs: url: https://badges.cssnr.com/ steps: + - name: "Checkout" + uses: actions/checkout@v6 + + - name: "Debug event.json" + if: ${{ !github.event.act }} + continue-on-error: true + run: cat "${GITHUB_EVENT_PATH}" - name: "Debug CTX github" if: ${{ !github.event.act }} continue-on-error: true env: GITHUB_CTX: ${{ toJSON(github) }} run: echo "$GITHUB_CTX" + - name: "Debug Environment" + if: ${{ !github.event.act }} + continue-on-error: true + run: env - name: "Debug 1" continue-on-error: true @@ -45,7 +58,7 @@ jobs: echo "env.version: ${{ env.version }}" - name: "Portainer Deploy" - uses: cssnr/portainer-stack-deploy-action@v1 + uses: cssnr/portainer-stack-deploy-action@v2 env: version: ${{ env.version == 'master' && 'latest' || env.version }} with: @@ -55,35 +68,27 @@ jobs: name: ${{ env.stack-name }} username: ${{ vars.GHCR_USER }} password: ${{ secrets.GHCR_PASS }} - env_json: | - { - "VERSION": "${{ env.version }}", - "STACK_NAME": "${{ env.stack-name }}", - "TRAEFIK_HOST": "${{ env.traefik-host }}", - "GITHUB_TOKEN": "${{ secrets.GH_PAT }}", - "VT_API_KEY": "${{ secrets.VT_API_KEY }}", - "SENTRY_URL": "${{ secrets.SENTRY_URL }}", - "SENTRY_ENVIRONMENT": "prod", - "INFLUX_URL": "${{ secrets.INFLUX_URL }}", - "INFLUX_TOKEN": "${{ secrets.INFLUX_TOKEN }}", - "INFLUX_ORG": "${{ vars.INFLUX_ORG }}", - "INFLUX_BUCKET": "${{ vars.INFLUX_BUCKET }}" - } + type: file + env_data: | + VERSION: "${{ env.version }}" + STACK_NAME: "${{ env.stack-name }}" + TRAEFIK_HOST: "${{ env.traefik-host }}" + GITHUB_TOKEN": "${{ secrets.GH_PAT }}" + VT_API_KEY": "${{ secrets.VT_API_KEY }}" + SENTRY_URL": "${{ secrets.SENTRY_URL }}" + SENTRY_ENVIRONMENT": "prod" + INFLUX_URL": "${{ secrets.INFLUX_URL }}" + INFLUX_TOKEN": "${{ secrets.INFLUX_TOKEN }}" + INFLUX_ORG": "${{ vars.INFLUX_ORG }}" + INFLUX_BUCKET": "${{ vars.INFLUX_BUCKET }} - #- name: "Debug 2" - # continue-on-error: true - # env: - # version: ${{ env.version == 'master' && 'latest' || env.version }} - # run: | - # echo "env.version: ${{ env.version }}" - # echo "ghcr.io/${{ github.repository }}:${{ env.version }}" - # ## https://render.com/docs/deploy-hooks#deploying-from-an-image-registry - #- name: "Render Deploy" + #- name: "Deploy Image" + # uses: cssnr/web-request-action@v2 # continue-on-error: true - # uses: cssnr/web-request-action@v1 # env: # version: ${{ env.version == 'master' && 'latest' || env.version }} # with: # url: ${{ secrets.RENDER_HOOK }} - # params: '{"imgURL": "ghcr.io/${{ github.repository }}:${{ env.version }}"}' + # params: | + # imgURL: ghcr.io/${{ github.repository }}:${{ env.version }} diff --git a/.github/workflows/draft.yaml b/.github/workflows/draft.yaml index 428fa06..7f93c65 100644 --- a/.github/workflows/draft.yaml +++ b/.github/workflows/draft.yaml @@ -3,9 +3,7 @@ name: "Draft Release" on: workflow_dispatch: push: - branches: ["master"] - release: - types: [published] + branches: [master, main] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml new file mode 100644 index 0000000..00dee8c --- /dev/null +++ b/.github/workflows/issue.yaml @@ -0,0 +1,35 @@ +name: "Issue" + +on: + issues: + types: [opened] + +jobs: + issue: + name: "Issue" + if: | + !github.event.issue.labels[0] || + contains(github.event.issue.labels.*.name, 'bug') + runs-on: ubuntu-latest + timeout-minutes: 15 + + permissions: + contents: write + issues: write + + steps: + - name: "Checkout" + uses: actions/checkout@v6 + + - name: "AI Issue" + uses: cssnr/ai-issue-action@v1 + with: + model: big-pickle + tail: | + _Response generated by the [AI Issue Action](https://github.com/cssnr/ai-issue-action)._ + instructions: | + You are a helpful assistant responding to a GitHub Issue created by user @${{ github.actor }} + in the repository ${{ github.server_url }}/${{ github.repository }} + Provide initial triage and troubleshooting steps, then gather any additional information needed to proceed. + Respond using your general knowledge and the following knowledge files: + url: https://smashedr.github.io/node-badges-docs/llms.txt diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml index 302ba3d..95030e5 100644 --- a/.github/workflows/labeler.yaml +++ b/.github/workflows/labeler.yaml @@ -3,6 +3,10 @@ name: "PR Labeler" on: pull_request_target: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: labeler: name: "Labeler" diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index c3e3989..4160d71 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -3,7 +3,7 @@ name: "Lint" on: workflow_dispatch: push: - branches: [master] + branches: [master, main] pull_request: concurrency: @@ -15,15 +15,34 @@ jobs: name: "Lint" runs-on: ubuntu-latest timeout-minutes: 5 - - permissions: - pull-requests: write - checks: write + if: ${{ !contains(github.event.head_commit.message, '#nolint') }} steps: - name: "Checkout" uses: actions/checkout@v6 + - name: "Setup Node" + uses: actions/setup-node@v6 + with: + node-version: 24 + + - name: "install" + id: install + run: npm ci + + - name: "Debug" + continue-on-error: true + run: ls -lahR dist + + - name: "eslint" + if: ${{ !cancelled() }} + run: | + npm run lint + + - name: "prettier" + if: ${{ !cancelled() }} + run: npm run prettier:check + - name: "yamllint" if: ${{ !cancelled() }} env: @@ -37,57 +56,10 @@ jobs: - name: "actionlint" if: ${{ !cancelled() }} uses: cssnr/actionlint-action@v1 - with: - shellcheck_opts: -e SC2129 - name: "hadolint" if: ${{ !cancelled() }} - uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0 + uses: hadolint/hadolint-action@v3.3.0 with: dockerfile: Dockerfile ignore: "DL3018" - - - name: "ShellCheck" - if: ${{ !cancelled() }} - uses: ludeeus/action-shellcheck@master - env: - SHELLCHECK_OPTS: -x - - #- name: "ESLint Annotate" - # if: ${{ !cancelled() && steps.eslint.outcome != 'success' }} - # continue-on-error: true - # uses: ataylorme/eslint-annotate-action@v3 - - npm-lint: - name: "NPM Lint" - runs-on: ubuntu-latest - timeout-minutes: 5 - - permissions: - pull-requests: write - checks: write - - steps: - - name: "Checkout" - uses: actions/checkout@v6 - - - name: "Setup Node" - uses: actions/setup-node@v6 - with: - node-version: 24 - - - name: "Install" - id: install - run: | - npm ci - - - name: "eslint" - id: eslint - if: ${{ !cancelled() }} - run: | - npm run lint - - - name: "prettier" - if: ${{ !cancelled() }} - run: | - npm run prettier:check diff --git a/.github/workflows/render.yaml b/.github/workflows/render.yaml index 03a9c42..e95d073 100644 --- a/.github/workflows/render.yaml +++ b/.github/workflows/render.yaml @@ -2,7 +2,7 @@ name: "Render" on: push: - branches-ignore: [master] + branches-ignore: [master, main] paths: - ".github/workflows/render.yaml" - "src/**" @@ -16,9 +16,6 @@ on: inputs: version: description: "Version Tag" - #workflow_run: - # workflows: ["Build"] - # types: [completed] env: version: ${{ inputs.version || github.ref_name }} @@ -37,14 +34,22 @@ jobs: url: https://node-badges.onrender.com/ steps: + - name: "Debug event.json" + if: ${{ !github.event.act }} + continue-on-error: true + run: cat "${GITHUB_EVENT_PATH}" - name: "Debug CTX github" if: ${{ !github.event.act }} continue-on-error: true env: GITHUB_CTX: ${{ toJSON(github) }} run: echo "$GITHUB_CTX" + - name: "Debug Environment" + if: ${{ !github.event.act }} + continue-on-error: true + run: env - - name: "Debug Branch ref" + - name: "Debug ref" continue-on-error: true run: | echo "github.ref_name: ${{ github.ref_name }}" @@ -53,7 +58,7 @@ jobs: echo "--------------------" echo "ref: ${{ github.ref_name }}" - - name: "Debug Image version" + - name: "Debug imgURL" continue-on-error: true env: version: ${{ env.version == 'master' && 'latest' || env.version }} @@ -82,4 +87,4 @@ jobs: with: url: ${{ secrets.RENDER_HOOK }} params: | - ref: ${{ github.ref_name }} + ref: ${{ github.sha }} diff --git a/.github/yamllint.yaml b/.github/yamllint.yaml index 38237e5..ccf5e5e 100644 --- a/.github/yamllint.yaml +++ b/.github/yamllint.yaml @@ -4,4 +4,4 @@ ignore-from-file: .gitignore rules: line-length: - max: 119 + max: 120 diff --git a/.gitignore b/.gitignore index e58e31f..56c667d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,15 +2,15 @@ .idea/ *.iml .vscode/ -.*cache* -node_modules/ -build/ +cache/ dist/ -out/ -*.dll -*.exe -.env +build/ +node_modules/ +eslint_report.json +*.log +*.tgz +*.zip +# App .secrets .vars -settings.env -eslint_report.json +*.env diff --git a/.prettierignore b/.prettierignore index db82eec..db2d326 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,8 @@ -.github/disabled -.github/pull_request_template.md +# Tools +dist/ package-lock.json + +# Files +.github/disabled/ +.github/PULL_REQUEST_TEMPLATE/ +.github/pull_request_template.md diff --git a/.prettierrc.json b/.prettierrc.json index f4f5ac9..2ec4058 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/prettierrc", "semi": false, "singleQuote": true, "printWidth": 90, @@ -9,12 +10,6 @@ "singleQuote": false, "printWidth": 120 } - }, - { - "files": ["**/*.js", "**/*.mjs", "**/*.css", "**/*.scss"], - "options": { - "tabWidth": 4 - } } ] } diff --git a/Dockerfile b/Dockerfile index bb09071..4e92254 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,6 @@ LABEL org.opencontainers.image.authors="smashedr" RUN apk add --no-cache curl -COPY docker-entrypoint.sh / - WORKDIR /app COPY package.json package-lock.json ./ @@ -25,5 +23,4 @@ LABEL org.opencontainers.image.version="${VERSION}" USER node -ENTRYPOINT ["sh", "/docker-entrypoint.sh"] CMD ["npm", "start"] diff --git a/docker-compose-swarm.yaml b/docker-compose-swarm.yaml index c1999fb..38db33d 100644 --- a/docker-compose-swarm.yaml +++ b/docker-compose-swarm.yaml @@ -15,18 +15,25 @@ services: memory: 64M labels: - "traefik.enable=true" - - "traefik.docker.network=traefik-public" - - "traefik.constraint-label=traefik-public" - - "traefik.http.routers.${STACK_NAME?err}-http.rule=Host(`${TRAEFIK_HOST?err}`)" - - "traefik.http.routers.${STACK_NAME}-http.entrypoints=http" - - "traefik.http.routers.${STACK_NAME}-http.middlewares=${STACK_NAME}-http-redirect" - - "traefik.http.middlewares.${STACK_NAME}-http-redirect.redirectscheme.scheme=https" - - "traefik.http.middlewares.${STACK_NAME}-http-redirect.redirectscheme.permanent=true" - - "traefik.http.routers.${STACK_NAME}-https.rule=Host(`${TRAEFIK_HOST}`)" - - "traefik.http.routers.${STACK_NAME}-https.entrypoints=https" - - "traefik.http.routers.${STACK_NAME}-https.tls=true" + - "traefik.http.routers.${STACK_NAME?err}.rule=Host(`${TRAEFIK_HOST?err}`)" + - "traefik.http.routers.${STACK_NAME}.entrypoints=https" + - "traefik.http.routers.${STACK_NAME}.tls=true" - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" - - "traefik.http.services.${STACK_NAME}.loadbalancer.server.scheme=http" + #- "traefik.http.routers.${STACK_NAME}.tls.certresolver=le" + + #- "traefik.enable=true" + #- "traefik.docker.network=traefik-public" + #- "traefik.constraint-label=traefik-public" + #- "traefik.http.routers.${STACK_NAME?err}-http.rule=Host(`${TRAEFIK_HOST?err}`)" + #- "traefik.http.routers.${STACK_NAME}-http.entrypoints=http" + #- "traefik.http.routers.${STACK_NAME}-http.middlewares=${STACK_NAME}-http-redirect" + #- "traefik.http.middlewares.${STACK_NAME}-http-redirect.redirectscheme.scheme=https" + #- "traefik.http.middlewares.${STACK_NAME}-http-redirect.redirectscheme.permanent=true" + #- "traefik.http.routers.${STACK_NAME}-https.rule=Host(`${TRAEFIK_HOST}`)" + #- "traefik.http.routers.${STACK_NAME}-https.entrypoints=https" + #- "traefik.http.routers.${STACK_NAME}-https.tls=true" + #- "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" + #- "traefik.http.services.${STACK_NAME}.loadbalancer.server.scheme=http" healthcheck: test: ["CMD-SHELL", "curl -sf localhost:80/health-check || exit 1"] interval: 30s diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh deleted file mode 100644 index 18864e2..0000000 --- a/docker-entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env sh - -set -ex - -exec "$@" diff --git a/eslint.config.mjs b/eslint.config.mjs index 74cf080..365ccb3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,21 +1,21 @@ import js from '@eslint/js' export default [ - js.configs.recommended, - { - languageOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - settings: { - env: { - node: true, - es2021: true, - }, - }, - rules: { - 'no-undef': 'off', - 'no-extra-semi': 'off', - }, + js.configs.recommended, + { + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', }, + settings: { + env: { + node: true, + es2021: true, + }, + }, + rules: { + 'no-undef': 'off', + 'no-extra-semi': 'off', + }, + }, ] diff --git a/package-lock.json b/package-lock.json index 09f858c..89aaa85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,8 @@ "dependencies": { "@influxdata/influxdb-client": "^1.35.0", "@octokit/rest": "^22.0.1", - "@sentry/node": "^10.45.0", - "axios": "^1.13.6", + "@sentry/node": "^10.57.0", + "axios": "^1.17.0", "badge-maker": "^5.0.2", "camelcase": "^9.0.0", "chroma-js": "^3.2.0", @@ -17,46 +17,46 @@ "debug": "^4.4.3", "express": "^5.2.1", "jsonpath": "^1.3.0", - "lucide-static": "^1.6.0", + "lucide-static": "^1.18.0", "node-schedule": "^2.1.1", "nodemon": "^3.1.14", "pug": "^3.0.4", - "redis": "^5.11.0", - "semver": "^7.7.4", - "simple-icons": "^16.13.0", - "yaml": "^2.8.3" + "redis": "^6.0.0", + "semver": "^7.8.4", + "simple-icons": "^16.23.0", + "yaml": "^2.9.0" }, "devDependencies": { "@eslint/js": "^10.0.1", - "eslint": "^10.1.0", - "prettier": "^3.8.1" + "eslint": "^10.5.0", + "prettier": "^3.8.4" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -66,13 +66,13 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -121,13 +121,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", - "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^3.0.3", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" }, @@ -136,22 +136,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", - "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.1" + "@eslint/core": "^1.2.1" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", - "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -183,9 +183,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", - "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -193,105 +193,53 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", - "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.1", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@fastify/otel": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@fastify/otel/-/otel-0.17.1.tgz", - "integrity": "sha512-K4wyxfUZx2ux5o+b6BtTqouYFVILohLZmSbA2tKUueJstNcBnoGPVhllCaOvbQ3ZrXdUxUC/fyrSWSCqHhdOPg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.212.0", - "@opentelemetry/semantic-conventions": "^1.28.0", - "minimatch": "^10.2.4" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0" - } - }, - "node_modules/@fastify/otel/node_modules/@opentelemetry/api-logs": { - "version": "0.212.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.212.0.tgz", - "integrity": "sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api": "^1.3.0" + "@humanfs/types": "^0.15.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=18.18.0" } }, - "node_modules/@fastify/otel/node_modules/@opentelemetry/instrumentation": { - "version": "0.212.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", - "integrity": "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.212.0", - "import-in-the-middle": "^2.0.6", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@fastify/otel/node_modules/import-in-the-middle": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", - "integrity": "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.15.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - } - }, - "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.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, "engines": { "node": ">=18.18.0" } @@ -433,15 +381,15 @@ } }, "node_modules/@octokit/request": { - "version": "10.0.8", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.8.tgz", - "integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==", + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.10.tgz", + "integrity": "sha512-KxNC2pTqqhszMNrf12ZRd4PonRgyJdsM4F/jySiddQK+DsRcfBtUvqn8t7UsyZhnRJHvX46OohDt5N3VqIWC2w==", "license": "MIT", "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", - "fast-content-type-parse": "^3.0.0", + "content-type": "^2.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" }, @@ -486,453 +434,65 @@ } }, "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.213.0.tgz", - "integrity": "sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.0.tgz", - "integrity": "sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", - "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.213.0.tgz", - "integrity": "sha512-3i9NdkET/KvQomeh7UaR/F4r9P25Rx6ooALlWXPIjypcEOUxksCmVu0zA70NBJWlrMW1rPr/LRidFAflLI+s/w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.213.0", - "import-in-the-middle": "^3.0.0", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.60.0.tgz", - "integrity": "sha512-q/B2IvoVXRm1M00MvhnzpMN6rKYOszPXVsALi6u0ss4AYHe+TidZEtLW9N1ZhrobI1dSriHnBqqtAOZVAv07sg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.56.0.tgz", - "integrity": "sha512-PKp+sSZ7AfzMvGgO3VCyo1inwNu+q7A1k9X88WK4PQ+S6Hp7eFk8pie+sWHDTaARovmqq5V2osav3lQej2B0nw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/connect": "3.4.38" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.30.0.tgz", - "integrity": "sha512-MXHP2Q38cd2OhzEBKAIXUi9uBlPEYzF6BNJbyjUXBQ6kLaf93kRC41vNMIz0Nl5mnuwK7fDvKT+/lpx7BXRwdg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.61.0.tgz", - "integrity": "sha512-Xdmqo9RZuZlL29Flg8QdwrrX7eW1CZ7wFQPKHyXljNymgKhN1MCsYuqQ/7uxavhSKwAl7WxkTzKhnqpUApLMvQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.32.0.tgz", - "integrity": "sha512-koR6apx0g0wX6RRiPpjA4AFQUQUbXrK16kq4/SZjVp7u5cffJhNkY4TnITxcGA4acGSPYAfx3NHRIv4Khn1axQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.56.0.tgz", - "integrity": "sha512-fg+Jffs6fqrf0uQS0hom7qBFKsbtpBiBl8+Vkc63Gx8xh6pVh+FhagmiO6oM0m3vyb683t1lP7yGYq22SiDnqg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.61.0.tgz", - "integrity": "sha512-pUiVASv6nh2XrerTvlbVHh7vKFzscpgwiQ/xvnZuAIzQ5lRjWVdRPUuXbvZJ/Yq79QsE81TZdJ7z9YsXiss1ew==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.59.0.tgz", - "integrity": "sha512-33wa4mEr+9+ztwdgLor1SeBu4Opz4IsmpcLETXAd3VmBrOjez8uQtrsOhPCa5Vhbm5gzDlMYTgFRLQzf8/YHFA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.213.0.tgz", - "integrity": "sha512-B978Xsm5XEPGhm1P07grDoaOFLHapJPkOG9h016cJsyWWxmiLnPu2M/4Nrm7UCkHSiLnkXgC+zVGUAIahy8EEA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.0", - "@opentelemetry/instrumentation": "0.213.0", - "@opentelemetry/semantic-conventions": "^1.29.0", - "forwarded-parse": "2.1.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.61.0.tgz", - "integrity": "sha512-hsHDadUtAFbws1YSDc1XW0svGFKiUbqv2td1Cby+UAiwvojm1NyBo/taifH0t8CuFZ0x/2SDm0iuTwrM5pnVOg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/redis-common": "^0.38.2", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.22.0.tgz", - "integrity": "sha512-wJU4IBQMUikdJAcTChLFqK5lo+flo7pahqd8DSLv7uMxsdOdAHj6RzKYAm8pPfUS6ItKYutYyuicwKaFwQKsoA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.30.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.57.0.tgz", - "integrity": "sha512-vMCSh8kolEm5rRsc+FZeTZymWmIJwc40hjIKnXH4O0Dv/gAkJJIRXCsPX5cPbe0c0j/34+PsENd0HqKruwhVYw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.61.0.tgz", - "integrity": "sha512-lvrfWe9ShK/D2X4brmx8ZqqeWPfRl8xekU0FCn7C1dHm5k6+rTOOi36+4fnaHAP8lig9Ux6XQ1D4RNIpPCt1WQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.36.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0" - } - }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.57.0.tgz", - "integrity": "sha512-cEqpUocSKJfwDtLYTTJehRLWzkZ2eoePCxfVIgGkGkb83fMB71O+y4MvRHJPbeV2bdoWdOVrl8uO0+EynWhTEA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.66.0.tgz", - "integrity": "sha512-d7m9QnAY+4TCWI4q1QRkfrc6fo/92VwssaB1DzQfXNRvu51b78P+HJlWP7Qg6N6nkwdb9faMZNBCZJfftmszkw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.59.0.tgz", - "integrity": "sha512-6/jWU+c1NgznkVLDU/2y0bXV2nJo3o9FWZ9mZ9nN6T/JBNRoMnVXZl2FdBmgH+a5MwaWLs5kmRJTP5oUVGIkPw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.59.0.tgz", - "integrity": "sha512-r+V/Fh0sm7Ga8/zk/TI5H5FQRAjwr0RrpfPf8kNIehlsKf12XnvIaZi8ViZkpX0gyPEpLXqzqWD6QHlgObgzZw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@types/mysql": "2.15.27" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.59.0.tgz", - "integrity": "sha512-n9/xrVCRBfG9egVbffnlU1uhr+HX0vF4GgtAB/Bvm48wpFgRidqD8msBMiym1kRYzmpWvJqTxNT47u1MkgBEdw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@opentelemetry/sql-common": "^0.41.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.65.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.65.0.tgz", - "integrity": "sha512-W0zpHEIEuyZ8zvb3njaX9AAbHgPYOsSWVOoWmv1sjVRSF6ZpBqtlxBWbU+6hhq1TFWBeWJOXZ8nZS/PUFpLJYQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.34.0", - "@opentelemetry/sql-common": "^0.41.2", - "@types/pg": "8.15.6", - "@types/pg-pool": "2.0.7" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/instrumentation-redis": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.61.0.tgz", - "integrity": "sha512-JnPexA034/0UJRsvH96B0erQoNOqKJZjE2ZRSw9hiTSC23LzE0nJE/u6D+xqOhgUhRnhhcPHq4MdYtmUdYTF+Q==", + "node_modules/@opentelemetry/api-logs": { + "version": "0.214.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.214.0.tgz", + "integrity": "sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/redis-common": "^0.38.2", - "@opentelemetry/semantic-conventions": "^1.27.0" + "@opentelemetry/api": "^1.3.0" }, "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.32.0.tgz", - "integrity": "sha512-BQS6gG8RJ1foEqfEZ+wxoqlwfCAzb1ZVG0ad8Gfe4x8T658HJCLGLd4E4NaoQd8EvPfLqOXgzGaE/2U4ytDSWA==", + "node_modules/@opentelemetry/core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@types/tedious": "^4.0.14" + "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/instrumentation-undici": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.23.0.tgz", - "integrity": "sha512-LL0VySzKVR2cJSFVZaTYpZl1XTpBGnfzoQPe2W7McS2267ldsaEIqtQY6VXs2KCXN0poFjze5110PIpxHDaDGg==", + "node_modules/@opentelemetry/instrumentation": { + "version": "0.214.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.214.0.tgz", + "integrity": "sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/semantic-conventions": "^1.24.0" + "@opentelemetry/api-logs": "0.214.0", + "import-in-the-middle": "^3.0.0", + "require-in-the-middle": "^8.0.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.7.0" - } - }, - "node_modules/@opentelemetry/redis-common": { - "version": "0.38.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.2.tgz", - "integrity": "sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@opentelemetry/api": "^1.3.0" } }, "node_modules/@opentelemetry/resources": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.0.tgz", - "integrity": "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.0", + "@opentelemetry/core": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -943,13 +503,13 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.0.tgz", - "integrity": "sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.8.0.tgz", + "integrity": "sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.0", - "@opentelemetry/resources": "2.6.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -960,199 +520,122 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", - "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", "license": "Apache-2.0", "engines": { "node": ">=14" } }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.2.tgz", - "integrity": "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "node_modules/@prisma/instrumentation": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-7.4.2.tgz", - "integrity": "sha512-r9JfchJF1Ae6yAxcaLu/V1TGqBhAuSDe3mRNOssBfx1rMzfZ4fdNvrgUBwyb/TNTGXFxlH9AZix5P257x07nrg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.207.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.8" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/api-logs": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.207.0.tgz", - "integrity": "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.207.0.tgz", - "integrity": "sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.207.0", - "import-in-the-middle": "^2.0.0", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@prisma/instrumentation/node_modules/import-in-the-middle": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", - "integrity": "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.15.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - } - }, "node_modules/@redis/bloom": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.11.0.tgz", - "integrity": "sha512-KYiVilAhAFN3057afUb/tfYJpsEyTkQB+tQcn5gVVA7DgcNOAj8lLxe4j8ov8BF6I9C1Fe/kwlbuAICcTMX8Lw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-6.0.0.tgz", + "integrity": "sha512-P0n5NkV9IIdT6nYXOfMHG83sho8pE7Nay7yw27wOGVLv4DthgvzebpGz6m7VuMTizeJmw3LPw2Xek5wFUhGpVw==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20.0.0" }, "peerDependencies": { - "@redis/client": "^5.11.0" + "@redis/client": "^6.0.0" } }, "node_modules/@redis/client": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.11.0.tgz", - "integrity": "sha512-GHoprlNQD51Xq2Ztd94HHV94MdFZQ3CVrpA04Fz8MVoHM0B7SlbmPEVIjwTbcv58z8QyjnrOuikS0rWF03k5dQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-6.0.0.tgz", + "integrity": "sha512-NS4iIT25r24sAjNQ2nSRdCW5jPJoV0rxkBee27oTeR+RXaOu89cjIsrww5rPBaYVGVdL1QCx9uz9141gZiSKdQ==", "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.2" }, "engines": { - "node": ">= 18" + "node": ">= 20.0.0" }, "peerDependencies": { - "@node-rs/xxhash": "^1.1.0" + "@node-rs/xxhash": "^1.1.0", + "@opentelemetry/api": ">=1 <2" }, "peerDependenciesMeta": { "@node-rs/xxhash": { "optional": true + }, + "@opentelemetry/api": { + "optional": true } } }, "node_modules/@redis/json": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.11.0.tgz", - "integrity": "sha512-1iAy9kAtcD0quB21RbPTbUqqy+T2Uu2JxucwE+B4A+VaDbIRvpZR6DMqV8Iqaws2YxJYB3GC5JVNzPYio2ErUg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-6.0.0.tgz", + "integrity": "sha512-F+eqFfgPcy57Zs1KW7UtLnBtRk6lxAUIoe7dyZerpm6e+ssYXG/dWJrbrHFYs0b7tt6QBtYpVuukBuM9XqhUAg==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20.0.0" }, "peerDependencies": { - "@redis/client": "^5.11.0" + "@redis/client": "^6.0.0" } }, "node_modules/@redis/search": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.11.0.tgz", - "integrity": "sha512-g1l7f3Rnyk/xI99oGHIgWHSKFl45Re5YTIcO8j/JE8olz389yUFyz2+A6nqVy/Zi031VgPDWscbbgOk8hlhZ3g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-6.0.0.tgz", + "integrity": "sha512-VHuCJ2W0YWFixGZh/l//8JiyOsD4gN+NhjdRAGIoUe0UQ4mtq1NyY2ZJ973XT+vYhaU21XdK8r8oNrd5n7wbzQ==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20.0.0" }, "peerDependencies": { - "@redis/client": "^5.11.0" + "@redis/client": "^6.0.0" } }, "node_modules/@redis/time-series": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.11.0.tgz", - "integrity": "sha512-TWFeOcU4xkj0DkndnOyhtxvX1KWD+78UHT3XX3x3XRBUGWeQrKo3jqzDsZwxbggUgf9yLJr/akFHXru66X5UQA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-6.0.0.tgz", + "integrity": "sha512-QWhkYsg+3lhBrBf+cbzybtV8LQcSrk7iXIgTaGU+pHNFTkql7TpVRE24ROS6M2ybVIV6O/zxTqfxgxxYiqyw0Q==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20.0.0" }, "peerDependencies": { - "@redis/client": "^5.11.0" + "@redis/client": "^6.0.0" + } + }, + "node_modules/@sentry-internal/server-utils": { + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/server-utils/-/server-utils-10.57.0.tgz", + "integrity": "sha512-Qu8ETmX/ITzteG7Im46b9HOxKKzeaIeqNvftaIlFURu1RUQdHbtGerS7QOmXzwnhuqNGNeiCQYkduB798IfRqA==", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.57.0" + }, + "engines": { + "node": ">=18" } }, "node_modules/@sentry/core": { - "version": "10.45.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.45.0.tgz", - "integrity": "sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==", + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.57.0.tgz", + "integrity": "sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@sentry/node": { - "version": "10.45.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.45.0.tgz", - "integrity": "sha512-Kpiq9lRGnJc1ex8SwxOBl+FLQNl4Y137BydVooP7AFiAYZ6ftwHsIEF1bcYXaipHMT1YHS2bdhC2UQaaB2jkuQ==", + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.57.0.tgz", + "integrity": "sha512-7KEStrJ97wPf1fA5nU5ONeTTcIIlh7oT8OMffEVA1PXmlhFoXhcQZVzr4rM+zj9tfMWT01og5Ng/Grgh3dN+FA==", "license": "MIT", "dependencies": { - "@fastify/otel": "0.17.1", - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.6.0", - "@opentelemetry/core": "^2.6.0", - "@opentelemetry/instrumentation": "^0.213.0", - "@opentelemetry/instrumentation-amqplib": "0.60.0", - "@opentelemetry/instrumentation-connect": "0.56.0", - "@opentelemetry/instrumentation-dataloader": "0.30.0", - "@opentelemetry/instrumentation-express": "0.61.0", - "@opentelemetry/instrumentation-fs": "0.32.0", - "@opentelemetry/instrumentation-generic-pool": "0.56.0", - "@opentelemetry/instrumentation-graphql": "0.61.0", - "@opentelemetry/instrumentation-hapi": "0.59.0", - "@opentelemetry/instrumentation-http": "0.213.0", - "@opentelemetry/instrumentation-ioredis": "0.61.0", - "@opentelemetry/instrumentation-kafkajs": "0.22.0", - "@opentelemetry/instrumentation-knex": "0.57.0", - "@opentelemetry/instrumentation-koa": "0.61.0", - "@opentelemetry/instrumentation-lru-memoizer": "0.57.0", - "@opentelemetry/instrumentation-mongodb": "0.66.0", - "@opentelemetry/instrumentation-mongoose": "0.59.0", - "@opentelemetry/instrumentation-mysql": "0.59.0", - "@opentelemetry/instrumentation-mysql2": "0.59.0", - "@opentelemetry/instrumentation-pg": "0.65.0", - "@opentelemetry/instrumentation-redis": "0.61.0", - "@opentelemetry/instrumentation-tedious": "0.32.0", - "@opentelemetry/instrumentation-undici": "0.23.0", - "@opentelemetry/resources": "^2.6.0", - "@opentelemetry/sdk-trace-base": "^2.6.0", + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/core": "^2.6.1", + "@opentelemetry/instrumentation": "^0.214.0", + "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", - "@prisma/instrumentation": "7.4.2", - "@sentry/core": "10.45.0", - "@sentry/node-core": "10.45.0", - "@sentry/opentelemetry": "10.45.0", + "@sentry-internal/server-utils": "10.57.0", + "@sentry/core": "10.57.0", + "@sentry/node-core": "10.57.0", + "@sentry/opentelemetry": "10.57.0", "import-in-the-middle": "^3.0.0" }, "engines": { @@ -1160,13 +643,13 @@ } }, "node_modules/@sentry/node-core": { - "version": "10.45.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.45.0.tgz", - "integrity": "sha512-KQZEvLKM344+EqXiA9HIzWbW5hzq6/9nnFUQ8niaBPoOgR9AiJhrccfIscfgb8vjkriiEtzE03OW/4h1CTgZ3Q==", + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.57.0.tgz", + "integrity": "sha512-2v2IF6MfTiu7pimWEq2rYhZsmlwyNbs3bHUsrYFPeP/Rpa6ObDuUWPdVEzJjfyK+AqqYZYxZdV0l3+B13kTEmQ==", "license": "MIT", "dependencies": { - "@sentry/core": "10.45.0", - "@sentry/opentelemetry": "10.45.0", + "@sentry/core": "10.57.0", + "@sentry/opentelemetry": "10.57.0", "import-in-the-middle": "^3.0.0" }, "engines": { @@ -1174,10 +657,9 @@ }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/resources": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" }, @@ -1185,16 +667,13 @@ "@opentelemetry/api": { "optional": true }, - "@opentelemetry/context-async-hooks": { - "optional": true - }, "@opentelemetry/core": { "optional": true }, - "@opentelemetry/instrumentation": { + "@opentelemetry/exporter-trace-otlp-http": { "optional": true }, - "@opentelemetry/resources": { + "@opentelemetry/instrumentation": { "optional": true }, "@opentelemetry/sdk-trace-base": { @@ -1206,33 +685,23 @@ } }, "node_modules/@sentry/opentelemetry": { - "version": "10.45.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.45.0.tgz", - "integrity": "sha512-PmuGO+p/gC3ZQ8ddOeJ5P9ApnTTm35i12Bpuyb13AckCbNSJFvG2ggZda35JQOmiFU0kKYiwkoFAa8Mvj9od3Q==", + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.57.0.tgz", + "integrity": "sha512-iwRz8cEK0GOISG34aJRO8GdYOk3nfpuT6dT2GDQrxw8f7JjkJKx9LPU8MaenOFa4MhY+Z02hI6NNcrbsoI3cXg==", "license": "MIT", "dependencies": { - "@sentry/core": "10.45.0" + "@sentry/core": "10.57.0" }, "engines": { "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -1241,9 +710,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1254,53 +723,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mysql": { - "version": "2.15.27", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", - "integrity": "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/pg": { - "version": "8.15.6", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.6.tgz", - "integrity": "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/pg-pool": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.7.tgz", - "integrity": "sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==", - "license": "MIT", - "dependencies": { - "@types/pg": "*" - } - }, - "node_modules/@types/tedious": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", - "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -1315,9 +737,9 @@ } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1345,10 +767,22 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1403,14 +837,15 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.17.0.tgz", + "integrity": "sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-walk": { @@ -1498,10 +933,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/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/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -1681,9 +1125,9 @@ } }, "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", "engines": { "node": ">=18" @@ -1694,12 +1138,16 @@ } }, "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==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cookie": { @@ -1877,9 +1325,9 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -1957,18 +1405,21 @@ } }, "node_modules/eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz", - "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", "dev": true, "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.3", - "@eslint/config-helpers": "^0.5.3", - "@eslint/core": "^1.1.1", - "@eslint/plugin-kit": "^0.6.1", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -2170,21 +1621,14 @@ "url": "https://opencollective.com/express" } }, - "node_modules/fast-content-type-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", - "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" + "node_modules/express/node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -2292,9 +1736,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -2312,16 +1756,16 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -2357,12 +1801,6 @@ "node": ">= 0.6" } }, - "node_modules/forwarded-parse": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", - "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", - "license": "MIT" - }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -2494,9 +1932,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2525,6 +1963,19 @@ "url": "https://opencollective.com/express" } }, + "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/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -2558,9 +2009,9 @@ "license": "ISC" }, "node_modules/import-in-the-middle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.0.tgz", - "integrity": "sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.2.tgz", + "integrity": "sha512-LGLYRl0A2gtyUJb2WDliBHmk6TtlHwdDjxonacZ8QrEs/ZW+YDgNv2QAfjRQWpS8HqvNcq6GGnN6jrOa5FysDQ==", "license": "Apache-2.0", "dependencies": { "acorn": "^8.15.0", @@ -2610,12 +2061,12 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -2808,9 +2259,9 @@ "license": "MIT" }, "node_modules/lucide-static": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.6.0.tgz", - "integrity": "sha512-w3KVwIKMbnvFKWgpDSoia4LRnZuV+ZMAkdvm7aVysXGsKaxWxuUS8kvO3IcvU3K0j9/1pR4IEVZ544b8KbgTCA==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.18.0.tgz", + "integrity": "sha512-0WRXLQnjbte5SXuzom6yfeGlVSFsEsC9rzxn66DZN0pXows3+N34CQHy3BHI1qA3uH7u/SUzx8LQhjeAnxd8JQ==", "license": "ISC" }, "node_modules/luxon": { @@ -2878,12 +2329,12 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -3099,46 +2550,15 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", - "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/picomatch": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", @@ -3151,45 +2571,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3201,9 +2582,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -3239,10 +2620,13 @@ } }, "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" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pstree.remy": { "version": "1.1.8", @@ -3385,9 +2769,9 @@ } }, "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -3436,19 +2820,19 @@ } }, "node_modules/redis": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-5.11.0.tgz", - "integrity": "sha512-YwXjATVDT+AuxcyfOwZn046aml9jMlQPvU1VXIlLDVAExe0u93aTfPYSeRgG4p9Q/Jlkj+LXJ1XEoFV+j2JKcQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-6.0.0.tgz", + "integrity": "sha512-n9Thfc39OXleEoPT2k5gwKsqY+HfCww3YS71ofcr9KKbkn89bpjU9dToIlD+JRdM3/GYQkwMtVgTxLyed+LptQ==", "license": "MIT", "dependencies": { - "@redis/bloom": "5.11.0", - "@redis/client": "5.11.0", - "@redis/json": "5.11.0", - "@redis/search": "5.11.0", - "@redis/time-series": "5.11.0" + "@redis/bloom": "6.0.0", + "@redis/client": "6.0.0", + "@redis/json": "6.0.0", + "@redis/search": "6.0.0", + "@redis/time-series": "6.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20.0.0" } }, "node_modules/require-in-the-middle": { @@ -3465,11 +2849,12 @@ } }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -3513,9 +2898,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3599,14 +2984,14 @@ } }, "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==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -3618,13 +3003,13 @@ } }, "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==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -3671,9 +3056,9 @@ } }, "node_modules/simple-icons": { - "version": "16.13.0", - "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.13.0.tgz", - "integrity": "sha512-N4AMZvFERU5YLEtUudtUesiM2H4O5xQ9qfS3K0oOV5II5KVtxOUAlmZ7KqBgiTSGBgCVkuLD/Z9dJKBtnI3kKQ==", + "version": "16.23.0", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.23.0.tgz", + "integrity": "sha512-08MaTpxj9zGYUIe38tfELYkaHiGE1YgbrbXmTBf+GPxi5mEqLSORQqOXrP0QKPdaFuzEDSmW5o4xkbLlFhmdCw==", "funding": [ { "type": "opencollective", @@ -3809,17 +3194,21 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/undefsafe": { @@ -3834,12 +3223,6 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "license": "MIT" }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "license": "MIT" - }, "node_modules/universal-user-agent": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", @@ -3930,19 +3313,10 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 62a56c9..d31757c 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "dependencies": { "@influxdata/influxdb-client": "^1.35.0", "@octokit/rest": "^22.0.1", - "@sentry/node": "^10.45.0", - "axios": "^1.13.6", + "@sentry/node": "^10.57.0", + "axios": "^1.17.0", "badge-maker": "^5.0.2", "camelcase": "^9.0.0", "chroma-js": "^3.2.0", @@ -23,18 +23,18 @@ "debug": "^4.4.3", "express": "^5.2.1", "jsonpath": "^1.3.0", - "lucide-static": "^1.6.0", + "lucide-static": "^1.18.0", "node-schedule": "^2.1.1", "nodemon": "^3.1.14", "pug": "^3.0.4", - "redis": "^5.11.0", - "semver": "^7.7.4", - "simple-icons": "^16.13.0", - "yaml": "^2.8.3" + "redis": "^6.0.0", + "semver": "^7.8.4", + "simple-icons": "^16.23.0", + "yaml": "^2.9.0" }, "devDependencies": { "@eslint/js": "^10.0.1", - "eslint": "^10.1.0", - "prettier": "^3.8.1" + "eslint": "^10.5.0", + "prettier": "^3.8.4" } } diff --git a/src/api.js b/src/api.js index 3c93e7a..55e8792 100644 --- a/src/api.js +++ b/src/api.js @@ -23,108 +23,109 @@ await client.connect() let influxClient if (process.env.INFLUX_URL && process.env.INFLUX_TOKEN) { - console.log(`INFLUX_URL: ${process.env.INFLUX_URL}`) - influxClient = new InfluxDB({ - url: process.env.INFLUX_URL, - token: process.env.INFLUX_TOKEN, - }) + console.log(`INFLUX_URL: ${process.env.INFLUX_URL}`) + influxClient = new InfluxDB({ + url: process.env.INFLUX_URL, + token: process.env.INFLUX_TOKEN, + }) } export class GHCRApi { - /** - * GHCR API - * @param {string} packageOwner - * @param {string} packageName - */ - constructor(packageOwner, packageName) { - if (!packageOwner || !packageName) throw new Error('Invalid Arguments') - this.packageOwner = packageOwner - this.packageName = packageName - this.token = Buffer.from(`v1:${packageOwner}/${packageName}:0`).toString('base64') - // noinspection JSCheckFunctionSignatures - this.client = axios.create({ - baseURL: 'https://ghcr.io/v2', - headers: { - accept: 'application/vnd.oci.image.index.v1+json,application/vnd.oci.image.manifest.v1+json', - 'x-github-api-version': '2022-11-28', - authorization: `Bearer ${this.token}`, - }, - }) - } + /** + * GHCR API + * @param {string} packageOwner + * @param {string} packageName + */ + constructor(packageOwner, packageName) { + if (!packageOwner || !packageName) throw new Error('Invalid Arguments') + this.packageOwner = packageOwner + this.packageName = packageName + this.token = Buffer.from(`v1:${packageOwner}/${packageName}:0`).toString('base64') + // noinspection JSCheckFunctionSignatures + this.client = axios.create({ + baseURL: 'https://ghcr.io/v2', + headers: { + accept: + 'application/vnd.oci.image.index.v1+json,application/vnd.oci.image.manifest.v1+json', + 'x-github-api-version': '2022-11-28', + authorization: `Bearer ${this.token}`, + }, + }) + } + + /** + * Get Image Tags + * @return {Promise} + */ + async getImageTags() { + const url = `${this.packageOwner}/${this.packageName}/tags/list` + const key = `ghcr/tags/${url}` + const cached = await cacheGet(key) + if (cached) return cached + debug(`-- CACHE MISS: ${key}`) - /** - * Get Image Tags - * @return {Promise} - */ - async getImageTags() { - const url = `${this.packageOwner}/${this.packageName}/tags/list` - const key = `ghcr/tags/${url}` - const cached = await cacheGet(key) - if (cached) return cached - debug(`-- CACHE MISS: ${key}`) - - const response = await this.client.get(url) - await cacheSet(key, response.data.tags) - return response.data.tags - } + const response = await this.client.get(url) + await cacheSet(key, response.data.tags) + return response.data.tags + } + + /** + * Get Image Size + * @return {Promise} + */ + async getImageSize(tag = 'latest') { + const key = `ghcr/size/${this.packageOwner}/${this.packageName}/${tag}` + const cached = await cacheGet(key) + if (cached) return cached + debug(`-- CACHE MISS: ${key}`) - /** - * Get Image Size - * @return {Promise} - */ - async getImageSize(tag = 'latest') { - const key = `ghcr/size/${this.packageOwner}/${this.packageName}/${tag}` - const cached = await cacheGet(key) - if (cached) return cached - debug(`-- CACHE MISS: ${key}`) - - const indexManifest = await this.getManifest(tag) - debug('mediaType:', indexManifest.mediaType) - - let totalSize = 0 - - if ( - !indexManifest.mediaType.includes('list') && - !indexManifest.mediaType.includes('index') - ) { - // debug('indexManifest - !list + !index:', indexManifest) - const size = indexManifest.layers.reduce((sum, layer) => sum + layer.size, 0) - totalSize = size + (indexManifest.config.size || 0) - // debug('totalSize:', totalSize) - await cacheSet(key, totalSize) - return totalSize - } - - debug('indexManifest.manifests?.length:', indexManifest.manifests?.length) - for (const m of indexManifest.manifests) { - await new Promise((resolve) => setTimeout(resolve, 50)) - const manifest = await this.getManifest(m.digest) - const configSize = manifest.config?.size || 0 - // debug('configSize:', configSize) - // noinspection JSUnresolvedReference - const layerSize = manifest.layers?.reduce((a, l) => a + (l.size || 0), 0) || 0 - // debug('layerSize:', layerSize) - totalSize += configSize + layerSize - } - // debug('totalSize:', totalSize) - await cacheSet(key, totalSize, 60 * 60 * 4) - return totalSize + const indexManifest = await this.getManifest(tag) + debug('mediaType:', indexManifest.mediaType) + + let totalSize = 0 + + if ( + !indexManifest.mediaType.includes('list') && + !indexManifest.mediaType.includes('index') + ) { + // debug('indexManifest - !list + !index:', indexManifest) + const size = indexManifest.layers.reduce((sum, layer) => sum + layer.size, 0) + totalSize = size + (indexManifest.config.size || 0) + // debug('totalSize:', totalSize) + await cacheSet(key, totalSize) + return totalSize } - /** - * Get Image Manifest - * @return {Promise} - */ - async getManifest(tag = 'latest') { - const url = `${this.packageOwner}/${this.packageName}/manifests/${tag}` - // debug('url:', url) - const response = await this.client.get(url) - return response.data + debug('indexManifest.manifests?.length:', indexManifest.manifests?.length) + for (const m of indexManifest.manifests) { + await new Promise((resolve) => setTimeout(resolve, 50)) + const manifest = await this.getManifest(m.digest) + const configSize = manifest.config?.size || 0 + // debug('configSize:', configSize) + // noinspection JSUnresolvedReference + const layerSize = manifest.layers?.reduce((a, l) => a + (l.size || 0), 0) || 0 + // debug('layerSize:', layerSize) + totalSize += configSize + layerSize } - - // getAuth(packageOwner, packageName) { - // return Buffer.from(`v1:${packageOwner}/${packageName}:0`).toString('base64') - // } + // debug('totalSize:', totalSize) + await cacheSet(key, totalSize, 60 * 60 * 4) + return totalSize + } + + /** + * Get Image Manifest + * @return {Promise} + */ + async getManifest(tag = 'latest') { + const url = `${this.packageOwner}/${this.packageName}/manifests/${tag}` + // debug('url:', url) + const response = await this.client.get(url) + return response.data + } + + // getAuth(packageOwner, packageName) { + // return Buffer.from(`v1:${packageOwner}/${packageName}:0`).toString('base64') + // } } /** @@ -133,63 +134,63 @@ export class GHCRApi { * @return {Promise} */ export async function getVTReleaseStats(req) { - const tag = req.params.tag || 'latest' - const key = `${req.params.owner}/${req.params.repo}/${req.params.asset}/${tag}` - debug('key:', key) - // NOTE: Duplicate Code - 5 lines - const cached = await cacheGet(key) - if (cached) { - if (cached.errorMessage) throw new Error(cached.errorMessage) - return cached - } - debug(`-- CACHE MISS: ${key}`) - - const release = await getRelease(req.params.owner, req.params.repo, tag) - // debug('release?.assets:', release?.assets) - if (!release) await cacheError(key, 'Release Not Found') - const asset = release.assets.find((a) => a.name === req.params.asset) - // debug('asset:', asset) - if (!asset) await cacheError(key, 'Asset Not Found') - // debug('asset?.digest:', asset?.digest) - if (!asset?.digest) await cacheError(key, 'Digest Not Found') - const hash = asset.digest.split(':')[1] - // debug('hash:', hash) - const stats = await getVTStats(hash) - // debug('last_analysis_stats:', stats) - if (!stats) await cacheError(key, 'VT Stats Not Found') - await cacheSet(key, stats) - return stats + const tag = req.params.tag || 'latest' + const key = `${req.params.owner}/${req.params.repo}/${req.params.asset}/${tag}` + debug('key:', key) + // NOTE: Duplicate Code - 5 lines + const cached = await cacheGet(key) + if (cached) { + if (cached.errorMessage) throw new Error(cached.errorMessage) + return cached + } + debug(`-- CACHE MISS: ${key}`) + + const release = await getRelease(req.params.owner, req.params.repo, tag) + // debug('release?.assets:', release?.assets) + if (!release) await cacheError(key, 'Release Not Found') + const asset = release.assets.find((a) => a.name === req.params.asset) + // debug('asset:', asset) + if (!asset) await cacheError(key, 'Asset Not Found') + // debug('asset?.digest:', asset?.digest) + if (!asset?.digest) await cacheError(key, 'Digest Not Found') + const hash = asset.digest.split(':')[1] + // debug('hash:', hash) + const stats = await getVTStats(hash) + // debug('last_analysis_stats:', stats) + if (!stats) await cacheError(key, 'VT Stats Not Found') + await cacheSet(key, stats) + return stats } export async function getGithubAssetSize(owner, repo, tag, name) { - const key = `/gh/release/${owner}/${repo}/${tag}/asset/${name}` - debug('key:', key) - const cached = await cacheGet(key) - if (cached) return cached - const release = await getRelease(owner, repo, tag) - // debug('release.assets:', release.assets) - if (!release.assets) return - const asset = release?.assets?.find((a) => a.name === name) - debug('asset:', asset) - if (!asset) return - debug('asset:', asset.size) - await cacheSet(key, asset.size) - return asset.size + const key = `/gh/release/${owner}/${repo}/${tag}/asset/${name}` + debug('key:', key) + const cached = await cacheGet(key) + if (cached) return cached + const release = await getRelease(owner, repo, tag) + // debug('release.assets:', release.assets) + if (!release.assets) return + const asset = release?.assets?.find((a) => a.name === name) + debug('asset:', asset) + if (!asset) return + debug('asset:', asset.size) + await cacheSet(key, asset.size) + return asset.size } async function getRelease(owner, repo, tag) { - const key = `/gh/release/${owner}/${repo}/${tag}` - const cached = await cacheGet(key) - if (cached) return cached - const gh = new GitHubApi(process.env.GITHUB_TOKEN) - let data - if (tag === 'latest') { - data = await gh.getLatestRelease(owner, repo) - } else { - data = await gh.getReleaseByTag(owner, repo, tag) - } - if (data) await cacheSet(key, data) - return data + const key = `/gh/release/${owner}/${repo}/${tag}` + const cached = await cacheGet(key) + if (cached) return cached + const gh = new GitHubApi(process.env.GITHUB_TOKEN) + let data + if (tag === 'latest') { + data = await gh.getLatestRelease(owner, repo) + } else { + data = await gh.getReleaseByTag(owner, repo, tag) + } + if (data) await cacheSet(key, data) + return data } /** @@ -202,54 +203,54 @@ async function getRelease(owner, repo, tag) { * @return {Promise} */ export async function getVTStats(hash) { - const key = `/vt/id/${hash}` - let timeout = 60 * 60 * 4 - debug('key:', key) - // NOTE: Duplicate Code - 5 lines - const cached = await cacheGet(key) - if (cached) { - if (cached.errorMessage) throw new Error(cached.errorMessage) - // client.expire(key, timeout).catch(console.error) // reset expire on get - return cached - } - debug(`-- CACHE MISS: ${key}`) - let stats, epoch, data - if (hash.endsWith('==')) { - debug('DEPRECATED - getAnalysis') // TODO: Deprecated - try { - data = await vtClient.getAnalysis(hash) - } catch (error) { - await cacheError(key, `Error ${error.status}`) - } - // debug('data:', JSON.stringify(data)) - stats = data?.data?.attributes?.stats - epoch = data?.data?.attributes?.date - } else { - try { - data = await vtClient.getReport(hash) - } catch (error) { - await cacheError(key, `Error ${error.status}`) - } - // debug('data:', JSON.stringify(data)) - // noinspection JSUnresolvedReference - stats = data?.data?.attributes?.last_analysis_stats - // noinspection JSUnresolvedReference - epoch = data?.data?.attributes?.last_analysis_date + const key = `/vt/id/${hash}` + let timeout = 60 * 60 * 4 + debug('key:', key) + // NOTE: Duplicate Code - 5 lines + const cached = await cacheGet(key) + if (cached) { + if (cached.errorMessage) throw new Error(cached.errorMessage) + // client.expire(key, timeout).catch(console.error) // reset expire on get + return cached + } + debug(`-- CACHE MISS: ${key}`) + let stats, epoch, data + if (hash.endsWith('==')) { + debug('DEPRECATED - getAnalysis') // TODO: Deprecated + try { + data = await vtClient.getAnalysis(hash) + } catch (error) { + await cacheError(key, `Error ${error.status}`) } - if (!stats) await cacheError(key, 'VT Stats Not Found') - if (typeof epoch === 'number') { - const date = new Date(0) - date.setUTCSeconds(epoch) - const now = new Date() - const ms = now.getTime() - date.getTime() - const hours = Math.floor(ms / 1000 / 60 / 60) - debug('hours:', hours) - if (hours > 4) timeout = 60 * 60 * 24 - if (hours > 48) timeout = 60 * 60 * 96 + // debug('data:', JSON.stringify(data)) + stats = data?.data?.attributes?.stats + epoch = data?.data?.attributes?.date + } else { + try { + data = await vtClient.getReport(hash) + } catch (error) { + await cacheError(key, `Error ${error.status}`) } - debug('timeout:', timeout) - await cacheSet(key, stats, timeout) - return stats + // debug('data:', JSON.stringify(data)) + // noinspection JSUnresolvedReference + stats = data?.data?.attributes?.last_analysis_stats + // noinspection JSUnresolvedReference + epoch = data?.data?.attributes?.last_analysis_date + } + if (!stats) await cacheError(key, 'VT Stats Not Found') + if (typeof epoch === 'number') { + const date = new Date(0) + date.setUTCSeconds(epoch) + const now = new Date() + const ms = now.getTime() - date.getTime() + const hours = Math.floor(ms / 1000 / 60 / 60) + debug('hours:', hours) + if (hours > 4) timeout = 60 * 60 * 24 + if (hours > 48) timeout = 60 * 60 * 96 + } + debug('timeout:', timeout) + await cacheSet(key, stats, timeout) + return stats } /** @@ -258,74 +259,74 @@ export async function getVTStats(hash) { * @return {Promise} */ export async function getJSONPath(req) { - const key = req.path - const cached = await cacheGet(key) - // debug('cached:', cached) - if (cached) return cached - debug(`-- CACHE MISS: ${key}`) - - const url = new URL(req.params.url) - debug('url.href:', url.href) - - const response = await fetch(url) - // debug('response:', response) - // debug('response.status:', response.status) - - // const length = response.headers.get('content-length') - // debug('content-length:', length) - - const text = await response.text() - // debug('text.length:', text.length) - // const encoder = new TextEncoder().encode(text) - // debug('encoder.length:', encoder.length) - - let data - if (req.params.type === 'yaml') { - data = parse(text) - } else { - data = JSON.parse(text) - } - // debug('data:', data) - - let result = jp.query(data, req.params.path)[0] + const key = req.path + const cached = await cacheGet(key) + // debug('cached:', cached) + if (cached) return cached + debug(`-- CACHE MISS: ${key}`) + + const url = new URL(req.params.url) + debug('url.href:', url.href) + + const response = await fetch(url) + // debug('response:', response) + // debug('response.status:', response.status) + + // const length = response.headers.get('content-length') + // debug('content-length:', length) + + const text = await response.text() + // debug('text.length:', text.length) + // const encoder = new TextEncoder().encode(text) + // debug('encoder.length:', encoder.length) + + let data + if (req.params.type === 'yaml') { + data = parse(text) + } else { + data = JSON.parse(text) + } + // debug('data:', data) + + let result = jp.query(data, req.params.path)[0] + debug('result:', result) + if (req.query.split) { + const split = result.split(req.query.split) + result = split[req.query.index || 0] debug('result:', result) - if (req.query.split) { - const split = result.split(req.query.split) - result = split[req.query.index || 0] - debug('result:', result) - } - if (!result) { - throw new Error('No Result for Query') - } else if (typeof result === 'object') { - throw new TypeError('Object Result') - } else { - result = result.toString() - await cacheSet(req.originalUrl, result) - return result - } + } + if (!result) { + throw new Error('No Result for Query') + } else if (typeof result === 'object') { + throw new TypeError('Object Result') + } else { + result = result.toString() + await cacheSet(req.originalUrl, result) + return result + } } export async function cacheGet(key, fallback = null) { - const cached = await client.get(key) - return cached ? JSON.parse(cached) : fallback + const cached = await client.get(key) + return cached ? JSON.parse(cached) : fallback } async function cacheSet(key, value, EX = 60 * 60) { - await client.set(key, JSON.stringify(value), { EX }) + await client.set(key, JSON.stringify(value), { EX }) } export async function cacheDelete(key) { - return await client.del(key) + return await client.del(key) } async function cacheError(key, errorMessage, EX = 60 * 10) { - debug(`cacheError: ${key}`, errorMessage) - await cacheSet(key, { errorMessage }, EX) - throw new Error(errorMessage) + debug(`cacheError: ${key}`, errorMessage) + await cacheSet(key, { errorMessage }, EX) + throw new Error(errorMessage) } export async function incrKey(key) { - await client.incr(key) + await client.incr(key) } // export async function incrPurge(result) { @@ -339,26 +340,26 @@ export async function incrKey(key) { // } export async function sendInflux() { - if (!influxClient) return debug('InfluxDB Not Configured.') - debug(`Processing Influx: ${new Date().toLocaleString()}`) + if (!influxClient) return debug('InfluxDB Not Configured.') + debug(`Processing Influx: ${new Date().toLocaleString()}`) - const org = process.env.INFLUX_ORG || 'cssnr' - const bucket = process.env.INFLUX_BUCKET || 'general' - const writeApi = influxClient.getWriteApi(org, bucket) + const org = process.env.INFLUX_ORG || 'cssnr' + const bucket = process.env.INFLUX_BUCKET || 'general' + const writeApi = influxClient.getWriteApi(org, bucket) - const measurementName = 'node_badges' + const measurementName = 'node_badges' - const write = (name, data) => { - const point = new Point(measurementName).intField(name, data) - debug('writePoint:', point) - writeApi.writePoint(point) - } + const write = (name, data) => { + const point = new Point(measurementName).intField(name, data) + debug('writePoint:', point) + writeApi.writePoint(point) + } - write('badges_total', await cacheGet('badges_total', 0)) - write('badges_404', await cacheGet('badges_404', 0)) - write('badges_error', await cacheGet('badges_error', 0)) - write('app_uptime', Math.floor(process.uptime())) - write('redis_keys', await client.dbSize()) + write('badges_total', await cacheGet('badges_total', 0)) + write('badges_404', await cacheGet('badges_404', 0)) + write('badges_error', await cacheGet('badges_error', 0)) + write('app_uptime', Math.floor(process.uptime())) + write('redis_keys', await client.dbSize()) - await writeApi.close() + await writeApi.close() } diff --git a/src/app.js b/src/app.js index 903b466..9fe6f0d 100644 --- a/src/app.js +++ b/src/app.js @@ -13,20 +13,20 @@ import { makeBadge } from 'badge-maker' import * as icons from 'simple-icons' import { - cacheDelete, - cacheGet, - getJSONPath, - getVTReleaseStats, - getVTStats, - GHCRApi, - incrKey, - getGithubAssetSize, - sendInflux, + cacheDelete, + cacheGet, + getJSONPath, + getVTReleaseStats, + getVTStats, + GHCRApi, + incrKey, + getGithubAssetSize, + sendInflux, } from './api.js' let Sentry if (process.env.SENTRY_URL) { - Sentry = await import('@sentry/node') + Sentry = await import('@sentry/node') } const debug = createDebug('app:app') @@ -48,50 +48,50 @@ console.log(`VT_API_KEY: ${process.env.VT_API_KEY ? 'Loaded' : 'MISSING'}`) console.log(`DEBUG: ${process.env.DEBUG || 'LOGGING OFF'}`) schedule.scheduleJob('*/5 * * * *', function () { - sendInflux().catch(console.error) + sendInflux().catch(console.error) }) const server = app.listen(port, () => { - console.log(`Listening on PORT: ${port}`) + console.log(`Listening on PORT: ${port}`) }) process.on('SIGTERM', () => { - console.log('SIGTERM signal received: closing server') - server.close(async (err) => { - console.log('server closed') - if (err) console.error(err) - // NOTE: Determine if this location is correct - await schedule.gracefulShutdown() - // NOTE: Determine if we should sendInflux on close - // await sendInflux() - process.exit(0) - }) + console.log('SIGTERM signal received: closing server') + server.close(async (err) => { + console.log('server closed') + if (err) console.error(err) + // NOTE: Determine if this location is correct + await schedule.gracefulShutdown() + // NOTE: Determine if we should sendInflux on close + // await sendInflux() + process.exit(0) + }) }) app.get('/app-health-check', (req, res) => { - res.sendStatus(200) + res.sendStatus(200) }) app.get('/', async (req, res) => { - const uptime = Math.floor(process.uptime()) - const fmt = (n) => Math.floor(n).toString().padStart(2, '0') - res.render('index', { - uptime, - seconds: uptime % 60, - minutes: fmt((uptime % 3600) / 60), - hours: fmt((uptime % 86400) / 3600), - days: Math.floor(uptime / 86400), - count: await cacheGet('badges_total', 0), - version: process.env.APP_VERSION, - title: 'Node Badges', - links: { - Source: 'https://github.com/smashedr/node-badges', - Docs: 'https://smashedr.github.io/node-badges-docs', - Grafana: - 'https://cssnr.grafana.net/public-dashboards/8a24a95171fe4127ada92afb071b9331', - }, - // badges: [{ src: '', href: '' }], - }) + const uptime = Math.floor(process.uptime()) + const fmt = (n) => Math.floor(n).toString().padStart(2, '0') + res.render('index', { + uptime, + seconds: uptime % 60, + minutes: fmt((uptime % 3600) / 60), + hours: fmt((uptime % 86400) / 3600), + days: Math.floor(uptime / 86400), + count: await cacheGet('badges_total', 0), + version: process.env.APP_VERSION, + title: 'Node Badges', + links: { + Source: 'https://github.com/smashedr/node-badges', + Docs: 'https://smashedr.github.io/node-badges-docs', + Grafana: + 'https://cssnr.grafana.net/public-dashboards/8a24a95171fe4127ada92afb071b9331', + }, + // badges: [{ src: '', href: '' }], + }) }) // app.get('/test{/:extra}', async (req, res) => { @@ -108,13 +108,13 @@ app.get('/', async (req, res) => { // }) app.get('/colors{/:index}', async (req, res) => { - debug(req.originalUrl) - const index = req.params.index || 0 - debug('index:', index) - const color = getRangedColor(req, index) - debug('color:', color) - // noinspection HtmlRequiredLangAttribute - res.send(``) + debug(req.originalUrl) + const index = req.params.index || 0 + debug('index:', index) + const color = getRangedColor(req, index) + debug('color:', color) + // noinspection HtmlRequiredLangAttribute + res.send(``) }) // app.use('/ghcr', (req, res, next) => { @@ -134,201 +134,201 @@ app.get('/colors{/:index}', async (req, res) => { // }) app.all('/vt/:type/:hash', async (req, res, next) => { - if (['PURGE', 'POST'].includes(req.method)) { - debug(`PURGE: ${req.method}`, req.originalUrl) - if (!['id', 'sha'].includes(req.params.type)) return next() - const hash = req.params.hash.includes(':') - ? req.params.hash.split(':')[1] - : req.params.hash - // debug('hash:', hash) - const key = `/vt/id/${hash}` - return purgeKey(res, key) - } - next() -}) - -app.get('/vt/:type/:hash', async (req, res) => { - debug(req.originalUrl) - // debug('req.params.type:', req.params.type) - if (!['id', 'sha'].includes(req.params.type)) return res.sendStatus(404) - if (!process.env.VT_API_KEY) throw new Error('Missing VT API Key') - + if (['PURGE', 'POST'].includes(req.method)) { + debug(`PURGE: ${req.method}`, req.originalUrl) + if (!['id', 'sha'].includes(req.params.type)) return next() const hash = req.params.hash.includes(':') - ? req.params.hash.split(':')[1] - : req.params.hash + ? req.params.hash.split(':')[1] + : req.params.hash // debug('hash:', hash) + const key = `/vt/id/${hash}` + return purgeKey(res, key) + } + next() +}) - const stats = await getVTStats(hash) - // debug('stats:', stats) - const message = `${stats.malicious}/${stats.suspicious}/${stats.undetected}` - // debug('message:', message) - const color = getRangedColor(req, stats.malicious + stats.suspicious) - const options = { label: hash.slice(0, 6), icon: 'virustotal', color } - getBadge(message, req.query, options, res) +app.get('/vt/:type/:hash', async (req, res) => { + debug(req.originalUrl) + // debug('req.params.type:', req.params.type) + if (!['id', 'sha'].includes(req.params.type)) return res.sendStatus(404) + if (!process.env.VT_API_KEY) throw new Error('Missing VT API Key') + + const hash = req.params.hash.includes(':') + ? req.params.hash.split(':')[1] + : req.params.hash + // debug('hash:', hash) + + const stats = await getVTStats(hash) + // debug('stats:', stats) + const message = `${stats.malicious}/${stats.suspicious}/${stats.undetected}` + // debug('message:', message) + const color = getRangedColor(req, stats.malicious + stats.suspicious) + const options = { label: hash.slice(0, 6), icon: 'virustotal', color } + getBadge(message, req.query, options, res) }) app.all('/vt/:owner/:repo/:asset{/:tag}', async (req, res, next) => { - if (['PURGE', 'POST'].includes(req.method)) { - debug(`PURGE: ${req.method}`, req.originalUrl) - const tag = req.params.tag || 'latest' - const key = `${req.params.owner}/${req.params.repo}/${req.params.asset}/${tag}` - return purgeKey(res, key) - } - next() + if (['PURGE', 'POST'].includes(req.method)) { + debug(`PURGE: ${req.method}`, req.originalUrl) + const tag = req.params.tag || 'latest' + const key = `${req.params.owner}/${req.params.repo}/${req.params.asset}/${tag}` + return purgeKey(res, key) + } + next() }) app.get('/vt/:owner/:repo/:asset{/:tag}', async (req, res) => { - debug(req.originalUrl) - if (!process.env.VT_API_KEY) throw new Error('Missing VT API Key') - const stats = await getVTReleaseStats(req) - // debug('stats:', stats) - const message = `${stats.malicious}/${stats.suspicious}/${stats.undetected}` - // debug('message:', message) - const color = getRangedColor(req, stats.malicious + stats.suspicious) - const options = { label: req.params.asset, icon: 'virustotal', color } - getBadge(message, req.query, options, res) + debug(req.originalUrl) + if (!process.env.VT_API_KEY) throw new Error('Missing VT API Key') + const stats = await getVTReleaseStats(req) + // debug('stats:', stats) + const message = `${stats.malicious}/${stats.suspicious}/${stats.undetected}` + // debug('message:', message) + const color = getRangedColor(req, stats.malicious + stats.suspicious) + const options = { label: req.params.asset, icon: 'virustotal', color } + getBadge(message, req.query, options, res) }) app.all('/ghcr/tags/:owner/:package{/:latest}', async (req, res, next) => { - if (['PURGE', 'POST'].includes(req.method)) { - debug(`PURGE: ${req.method}`, req.originalUrl) - const key = `ghcr/tags/${req.params.owner}/${req.params.package}/tags/list` - return purgeKey(res, key) - } - next() + if (['PURGE', 'POST'].includes(req.method)) { + debug(`PURGE: ${req.method}`, req.originalUrl) + const key = `ghcr/tags/${req.params.owner}/${req.params.package}/tags/list` + return purgeKey(res, key) + } + next() }) app.get('/ghcr/tags/:owner/:package{/:latest}', async (req, res) => { - debug(req.originalUrl) - if (req.params.latest && req.params.latest !== 'latest') { - return res.sendStatus(404) - } - const count = Number.parseInt(req.query.n) || 3 - // debug('count:', count) - - const api = new GHCRApi(req.params.owner, req.params.package) - let tags = await api.getImageTags() - tags = tags.filter((tag) => tag !== 'latest') - tags = tags.toReversed() - - if (req.query.semver !== undefined) { - tags = tags.filter((str) => semver.valid(str)) - } - - tags = tags.slice(0, count) - tags = tags.toSorted((a, b) => a.localeCompare(b, undefined, { numeric: true })) - - if (req.params.latest) { - const message = tags.at(-1) - // debug('latest - message:', message) - return getBadge(message, req.query, { label: 'latest', lucide: 'tag' }, res) - } - - if (req.query.reversed !== undefined) { - tags.reverse() - } - - const message = tags.join(` ${req.query.sep || '|'} `) - // debug('tags - message:', message) - getBadge(message, req.query, { label: 'tags', lucide: 'tags' }, res) + debug(req.originalUrl) + if (req.params.latest && req.params.latest !== 'latest') { + return res.sendStatus(404) + } + const count = Number.parseInt(req.query.n) || 3 + // debug('count:', count) + + const api = new GHCRApi(req.params.owner, req.params.package) + let tags = await api.getImageTags() + tags = tags.filter((tag) => tag !== 'latest') + tags = tags.toReversed() + + if (req.query.semver !== undefined) { + tags = tags.filter((str) => semver.valid(str)) + } + + tags = tags.slice(0, count) + tags = tags.toSorted((a, b) => a.localeCompare(b, undefined, { numeric: true })) + + if (req.params.latest) { + const message = tags.at(-1) + // debug('latest - message:', message) + return getBadge(message, req.query, { label: 'latest', lucide: 'tag' }, res) + } + + if (req.query.reversed !== undefined) { + tags.reverse() + } + + const message = tags.join(` ${req.query.sep || '|'} `) + // debug('tags - message:', message) + getBadge(message, req.query, { label: 'tags', lucide: 'tags' }, res) }) app.all('/ghcr/size/:owner/:package{/:tag}', async (req, res, next) => { - if (['PURGE', 'POST'].includes(req.method)) { - debug(`PURGE: ${req.method}`, req.originalUrl) - const tag = req.params.tag ? req.params.tag : 'latest' - const key = `ghcr/size/${req.params.owner}/${req.params.package}/${tag}` - return purgeKey(res, key) - } - next() + if (['PURGE', 'POST'].includes(req.method)) { + debug(`PURGE: ${req.method}`, req.originalUrl) + const tag = req.params.tag ? req.params.tag : 'latest' + const key = `ghcr/size/${req.params.owner}/${req.params.package}/${tag}` + return purgeKey(res, key) + } + next() }) app.get('/ghcr/size/:owner/:package{/:tag}', async (req, res) => { - debug(req.originalUrl) + debug(req.originalUrl) - const api = new GHCRApi(req.params.owner, req.params.package) - const tag = req.params.tag || 'latest' - const total = await api.getImageSize(tag) - // debug('getImageSize - total:', total) + const api = new GHCRApi(req.params.owner, req.params.package) + const tag = req.params.tag || 'latest' + const total = await api.getImageSize(tag) + // debug('getImageSize - total:', total) - const message = formatSize(total) - // debug('message:', message) - getBadge(message, req.query, { label: 'size', lucide: 'container' }, res) + const message = formatSize(total) + // debug('message:', message) + getBadge(message, req.query, { label: 'size', lucide: 'container' }, res) }) app.get('/gh/release/:owner/:repo/:tag/asset/:asset/size', async (req, res) => { - debug(req.originalUrl) - debug('owner:', req.params.owner) - debug('repo:', req.params.repo) - debug('tag:', req.params.tag) - debug('asset:', req.params.asset) - - const result = await getGithubAssetSize( - req.params.owner, - req.params.repo, - req.params.tag, - req.params.asset, - ) - debug('result:', result) - if (result) { - const message = formatSize(result) - // debug('message:', message) - getBadge(message, req.query, { label: req.params.asset, lucide: 'database' }, res) - } + debug(req.originalUrl) + debug('owner:', req.params.owner) + debug('repo:', req.params.repo) + debug('tag:', req.params.tag) + debug('asset:', req.params.asset) + + const result = await getGithubAssetSize( + req.params.owner, + req.params.repo, + req.params.tag, + req.params.asset, + ) + debug('result:', result) + if (result) { + const message = formatSize(result) + // debug('message:', message) + getBadge(message, req.query, { label: req.params.asset, lucide: 'database' }, res) + } }) app.get('/static/:message{/:label}', async (req, res) => { - debug(req.originalUrl) - // debug(`message/label: ${req.params.message} / ${req.params.label}`) - // NOTE: This endpoint uses custom logic to make a "static" badge - // This needs to be fixed, the icon does not show up like shields - const query = structuredClone(req.query) - if (!req.params.label && !query.label && !query.labelColor) { - query.labelColor = query.color || 'brightgreen' - } - // debug('query:', query) - getBadge(req.params.message, query, { label: req.params.label }, res) + debug(req.originalUrl) + // debug(`message/label: ${req.params.message} / ${req.params.label}`) + // NOTE: This endpoint uses custom logic to make a "static" badge + // This needs to be fixed, the icon does not show up like shields + const query = structuredClone(req.query) + if (!req.params.label && !query.label && !query.labelColor) { + query.labelColor = query.color || 'brightgreen' + } + // debug('query:', query) + getBadge(req.params.message, query, { label: req.params.label }, res) }) app.all('/:type/:url/:path', async (req, res, next) => { - if (!['yaml', 'json'].includes(req.params.type)) return next() - if (['PURGE', 'POST'].includes(req.method)) { - debug(`PURGE: ${req.method}`, req.originalUrl) - return purgeKey(res, req.path) - } - next() + if (!['yaml', 'json'].includes(req.params.type)) return next() + if (['PURGE', 'POST'].includes(req.method)) { + debug(`PURGE: ${req.method}`, req.originalUrl) + return purgeKey(res, req.path) + } + next() }) app.get('/:type/:url/:path', async (req, res) => { - debug(req.originalUrl) - // debug('req.params.type:', req.params.type) - if (!['yaml', 'json'].includes(req.params.type)) return res.sendStatus(404) + debug(req.originalUrl) + // debug('req.params.type:', req.params.type) + if (!['yaml', 'json'].includes(req.params.type)) return res.sendStatus(404) - const message = await getJSONPath(req) - // debug('message:', message) - getBadge(message, req.query, { label: 'result', lucide: 'code-xml' }, res) + const message = await getJSONPath(req) + // debug('message:', message) + getBadge(message, req.query, { label: 'result', lucide: 'code-xml' }, res) }) app.get('/uptime', async (req, res) => { - debug(req.originalUrl) - const message = getUptime() - // debug('message:', message) - getBadge(message, req.query, { label: 'uptime', lucide: 'clock-arrow-up' }, res) + debug(req.originalUrl) + const message = getUptime() + // debug('message:', message) + getBadge(message, req.query, { label: 'uptime', lucide: 'clock-arrow-up' }, res) }) // Handler - 404 app.use((req, res) => { - debug('404 - originalUrl:', req.originalUrl) - const data = { - message: '404 - URL Not Found', - color: 'red', - style: req.query.style || 'flat', - } - debug('404 data:', data) - // noinspection JSCheckFunctionSignatures - const badge = makeBadge(data) - sendBadge(res, badge, 404) - incrKey('badges_404').catch(console.error) + debug('404 - originalUrl:', req.originalUrl) + const data = { + message: '404 - URL Not Found', + color: 'red', + style: req.query.style || 'flat', + } + debug('404 data:', data) + // noinspection JSCheckFunctionSignatures + const badge = makeBadge(data) + sendBadge(res, badge, 404) + incrKey('badges_404').catch(console.error) }) // Error Handler @@ -340,22 +340,22 @@ app.use(errorHandler) if (Sentry) Sentry.setupExpressErrorHandler(app) function errorHandler(err, req, res, next) { - // console.log('errorHandler:', err) - debug('errorHandler - originalUrl:', req.originalUrl) - debug('err.message:', err.message) - if (res.headersSent) { - debug('SKIPPING: Headers Sent') - return next(err) - } - const data = { - message: err.message || 'Unknown Error', - color: 'red', - style: req.query.style || 'flat', - } - debug('data:', data) - const badge = makeBadge(data) - sendBadge(res, badge) - incrKey('badges_error').catch(console.error) + // console.log('errorHandler:', err) + debug('errorHandler - originalUrl:', req.originalUrl) + debug('err.message:', err.message) + if (res.headersSent) { + debug('SKIPPING: Headers Sent') + return next(err) + } + const data = { + message: err.message || 'Unknown Error', + color: 'red', + style: req.query.style || 'flat', + } + debug('data:', data) + const badge = makeBadge(data) + sendBadge(res, badge) + incrKey('badges_error').catch(console.error) } /** @@ -363,8 +363,8 @@ function errorHandler(err, req, res, next) { * @param {express.Response} res */ function setHeaders(res) { - res.setHeader('Content-Type', 'image/svg+xml') - res.setHeader('Cache-Control', 'public, max-age=3600') + res.setHeader('Content-Type', 'image/svg+xml') + res.setHeader('Cache-Control', 'public, max-age=3600') } /** @@ -374,8 +374,8 @@ function setHeaders(res) { * @param {number} [status] */ function sendBadge(res, badge, status = 200) { - setHeaders(res) - res.status(status).send(badge) + setHeaders(res) + res.status(status).send(badge) } /** @@ -387,25 +387,25 @@ function sendBadge(res, badge, status = 200) { * @return {string} */ function getBadge(message, query = {}, options = {}, res = null) { - const opts = { color: '', label: '', icon: '', lucide: '', ...options } - // debug('--- opts:', opts) - const data = { - message: message.toString(), - color: query.color || opts.color || 'brightgreen', - style: query.style || 'flat', - } - const label = query.label !== undefined ? query.label : opts.label - if (label) data.label = label - const logo = getLogo(query, opts) - if (logo) { - data.logoBase64 = `data:image/svg+xml;base64,${logo}` - data.labelColor = query.labelColor || '#555' - } - // debug('data:', data) - const badge = makeBadge(data) - if (res) sendBadge(res, badge) - incrKey('badges_total').catch(console.error) - return badge + const opts = { color: '', label: '', icon: '', lucide: '', ...options } + // debug('--- opts:', opts) + const data = { + message: message.toString(), + color: query.color || opts.color || 'brightgreen', + style: query.style || 'flat', + } + const label = query.label !== undefined ? query.label : opts.label + if (label) data.label = label + const logo = getLogo(query, opts) + if (logo) { + data.logoBase64 = `data:image/svg+xml;base64,${logo}` + data.labelColor = query.labelColor || '#555' + } + // debug('data:', data) + const badge = makeBadge(data) + if (res) sendBadge(res, badge) + incrKey('badges_total').catch(console.error) + return badge } /** @@ -416,36 +416,36 @@ function getBadge(message, query = {}, options = {}, res = null) { * @return {string} */ function getLogo(query, opts, color = '#fff') { - // debug('query.icon:', query.icon) - if (query.icon !== undefined && !query.icon) return '' - const iconName = query.icon || query.lucide || opts.icon || opts.lucide - // debug('iconName:', iconName) - - const name = camelCase(iconName, { pascalCase: true }) - // debug('name:', name) - if (!name) return '' - - let svg, colorType - if ((query.icon || opts.icon) && !query.lucide) { - // debug('Simple Icons') - svg = icons[`si${name}`]?.svg - colorType = 'fill' - } else { - // debug('Lucide Icon') - svg = lucide[name] - colorType = 'color' - } - - if (!svg) { - console.warn(`SVG NOT FOUND - icon: ${iconName} - name: ${name}`) - return '' - } - - const iconColor = query.iconColor || color - // debug('iconColor:', iconColor) - const result = svg.replace('} */ async function purgeKey(res, key) { - debug(`purgeKey: ${key}`) - const result = await cacheDelete(key) - debug('result:', result) - res.send(result.toString()) - if (result) { - incrKey('purge_hit').catch(console.error) - } else { - incrKey('purge_miss').catch(console.error) - } + debug(`purgeKey: ${key}`) + const result = await cacheDelete(key) + debug('result:', result) + res.send(result.toString()) + if (result) { + incrKey('purge_hit').catch(console.error) + } else { + incrKey('purge_miss').catch(console.error) + } } /** @@ -472,10 +472,10 @@ async function purgeKey(res, key) { * @return {string} */ function formatSize(bytes) { - if (bytes === 0) return '0 B' - const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] - const i = Math.floor(Math.log(bytes) / Math.log(1024)) - return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + units[i] + if (bytes === 0) return '0 B' + const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] + const i = Math.floor(Math.log(bytes) / Math.log(1024)) + return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + units[i] } /** @@ -483,14 +483,14 @@ function formatSize(bytes) { * @return {string} */ function getUptime() { - const seconds = process.uptime() - if (seconds < 60) return `${Math.floor(seconds)} sec` - const minutes = seconds / 60 - if (minutes < 60) return `${Math.floor(minutes)} min` - const hours = minutes / 60 - if (hours < 24) return `${Math.floor(hours)} hrs` - const days = hours / 24 - return `${Math.floor(days)} days` + const seconds = process.uptime() + if (seconds < 60) return `${Math.floor(seconds)} sec` + const minutes = seconds / 60 + if (minutes < 60) return `${Math.floor(minutes)} min` + const hours = minutes / 60 + if (hours < 24) return `${Math.floor(hours)} hrs` + const days = hours / 24 + return `${Math.floor(days)} days` } /** @@ -501,17 +501,17 @@ function getUptime() { * @return {string} */ function getRangedColor(req, index, options = {}) { - const opts = { total: 8, start: '#44cc11', end: '#e05d44', ...options } - opts.total = Number.parseInt(req.query.n || opts.total) - opts.start = req.query.start || opts.start - opts.end = req.query.end || opts.end - const colors = chroma - .scale([opts.start, opts.end]) - .mode('lab') - .colors(opts.total + 1) - // debug('colors:', colors) - // colors.forEach((color) => debug(color)) - const idx = Math.max(0, Math.min(opts.total, index)) - // debug(`index: ${idx} / ${colors.length - 1}`) - return colors[idx] + const opts = { total: 8, start: '#44cc11', end: '#e05d44', ...options } + opts.total = Number.parseInt(req.query.n || opts.total) + opts.start = req.query.start || opts.start + opts.end = req.query.end || opts.end + const colors = chroma + .scale([opts.start, opts.end]) + .mode('lab') + .colors(opts.total + 1) + // debug('colors:', colors) + // colors.forEach((color) => debug(color)) + const idx = Math.max(0, Math.min(opts.total, index)) + // debug(`index: ${idx} / ${colors.length - 1}`) + return colors[idx] } diff --git a/src/github.js b/src/github.js index 6ef233a..67c8618 100644 --- a/src/github.js +++ b/src/github.js @@ -4,66 +4,66 @@ import { Octokit } from '@octokit/rest' export const debug = createDebug('app:api') export class GitHubApi { - /** - * GitHub Api - * @param {string} [token] - */ - constructor(token) { - const data = {} - if (token) data.token = token - this.octokit = new Octokit(data) - } + /** + * GitHub Api + * @param {string} [token] + */ + constructor(token) { + const data = {} + if (token) data.token = token + this.octokit = new Octokit(data) + } - // /** - // * Get Release - // * @param {string} release_id - // * @return {Promise} - // */ - // async getRelease(release_id) { - // debug('getRelease:', release_id) - // const response = await this.octokit.rest.repos.getRelease({ - // ...github.context.repo, - // release_id, - // }) - // debug('response.status:', response.status) - // return response.data - // } + // /** + // * Get Release + // * @param {string} release_id + // * @return {Promise} + // */ + // async getRelease(release_id) { + // debug('getRelease:', release_id) + // const response = await this.octokit.rest.repos.getRelease({ + // ...github.context.repo, + // release_id, + // }) + // debug('response.status:', response.status) + // return response.data + // } - /** - * Get Release by Tag - * @param {string} owner - * @param {string} repo - * @param {string} tag - * @return {Promise} - */ - async getReleaseByTag(owner, repo, tag) { - debug('getReleaseByTag:', tag) - const response = await this.octokit.rest.repos.getReleaseByTag({ - owner, - repo, - tag, - }) - debug('response.status:', response.status) - return response.data - } + /** + * Get Release by Tag + * @param {string} owner + * @param {string} repo + * @param {string} tag + * @return {Promise} + */ + async getReleaseByTag(owner, repo, tag) { + debug('getReleaseByTag:', tag) + const response = await this.octokit.rest.repos.getReleaseByTag({ + owner, + repo, + tag, + }) + debug('response.status:', response.status) + return response.data + } - /** - * Get Latest Release - * @param {string} owner - * @param {string} repo - * @return {Promise} - */ - async getLatestRelease(owner, repo) { - debug('getLatestRelease:', owner, repo) - try { - const response = await this.octokit.rest.repos.getLatestRelease({ - owner, - repo, - }) - debug('response.status:', response.status) - return response.data - } catch (error) { - console.error('error:', error) - } + /** + * Get Latest Release + * @param {string} owner + * @param {string} repo + * @return {Promise} + */ + async getLatestRelease(owner, repo) { + debug('getLatestRelease:', owner, repo) + try { + const response = await this.octokit.rest.repos.getLatestRelease({ + owner, + repo, + }) + debug('response.status:', response.status) + return response.data + } catch (error) { + console.error('error:', error) } + } } diff --git a/src/instrument.js b/src/instrument.js index 84d4ba0..71ffcab 100644 --- a/src/instrument.js +++ b/src/instrument.js @@ -1,13 +1,13 @@ if (process.env.SENTRY_URL) { - const environment = process.env.SENTRY_ENVIRONMENT || 'dev' - console.log(`SENTRY_ENVIRONMENT: ${environment}`) - console.log(`SENTRY_URL: ${process.env.SENTRY_URL.substring(0, 14)}...`) - const Sentry = await import('@sentry/node') - // https://docs.sentry.io/platforms/javascript/configuration/options/ - Sentry.init({ - dsn: process.env.SENTRY_URL, - environment, - }) + const environment = process.env.SENTRY_ENVIRONMENT || 'dev' + console.log(`SENTRY_ENVIRONMENT: ${environment}`) + console.log(`SENTRY_URL: ${process.env.SENTRY_URL.substring(0, 14)}...`) + const Sentry = await import('@sentry/node') + // https://docs.sentry.io/platforms/javascript/configuration/options/ + Sentry.init({ + dsn: process.env.SENTRY_URL, + environment, + }) } else { - console.log('SENTRY_URL: MISSING') + console.log('SENTRY_URL: MISSING') } diff --git a/src/virustotal.js b/src/virustotal.js index adf6e6b..e4984a9 100644 --- a/src/virustotal.js +++ b/src/virustotal.js @@ -4,51 +4,51 @@ import createDebug from 'debug' const debug = createDebug('app:api') export class VTApi { - /** - * VirusTotal API - * @param {string} tokens - CSV of API tokens - */ - constructor(tokens) { - this.tokens = tokens - .split(',') - .map((t) => t.trim()) - .filter(Boolean) - // debug('this.tokens:', this.tokens) - console.log(`Loaded ${this.tokens.length} VT API Keys`) + /** + * VirusTotal API + * @param {string} tokens - CSV of API tokens + */ + constructor(tokens) { + this.tokens = tokens + .split(',') + .map((t) => t.trim()) + .filter(Boolean) + // debug('this.tokens:', this.tokens) + console.log(`Loaded ${this.tokens.length} VT API Keys`) - this.idx = 0 + this.idx = 0 - this.client = axios.create({ - baseURL: 'https://www.virustotal.com/api/v3/', - }) + this.client = axios.create({ + baseURL: 'https://www.virustotal.com/api/v3/', + }) - this.client.interceptors.request.use((config) => { - config.headers['X-APIKey'] = this.tokens[this.idx] - this.idx = (this.idx + 1) % this.tokens.length - debug('Using token index %d/%d', this.idx, this.tokens.length) - return config - }) - } + this.client.interceptors.request.use((config) => { + config.headers['X-APIKey'] = this.tokens[this.idx] + this.idx = (this.idx + 1) % this.tokens.length + debug('Using token index %d/%d', this.idx, this.tokens.length) + return config + }) + } - /** - * Get Report - * @param {string} id - * @return {Promise} - */ - async getReport(id) { - const response = await this.client.get(`/files/${id}`) - debug('getReport: response.status:', response.status) - return response.data - } + /** + * Get Report + * @param {string} id + * @return {Promise} + */ + async getReport(id) { + const response = await this.client.get(`/files/${id}`) + debug('getReport: response.status:', response.status) + return response.data + } - /** - * Get Analysis - * @param {string} id - * @return {Promise} - */ - async getAnalysis(id) { - const response = await this.client.get(`/analyses/${id}`) - debug('getAnalysis: response.status:', response.status) - return response.data - } + /** + * Get Analysis + * @param {string} id + * @return {Promise} + */ + async getAnalysis(id) { + const response = await this.client.get(`/analyses/${id}`) + debug('getAnalysis: response.status:', response.status) + return response.data + } }