diff --git a/.dockerignore b/.dockerignore index 6ed48a9..66bedec 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ .env node_modules +.git diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..899fb1a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: npm + directory: "/" + schedule: + interval: daily + time: '20:00' + open-pull-requests-limit: 10 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b713171 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "protobufs"] + path = src/protobufs + url = https://github.com/meshtastic/protobufs.git diff --git a/Dockerfile b/Dockerfile index 7595149..4094a66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,29 @@ -FROM node:lts-alpine +FROM node:lts-alpine AS build + +RUN apk add --no-cache openssl -# add project files to /app -ADD ./ /app WORKDIR /app -# install node dependencies -RUN npm install +# Copy only package files and install deps +# This layer will be cached as long as package*.json don't change +COPY package*.json package-lock.json* ./ +RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev + +# Copy the rest of your source +COPY . . + +# Pre-generate prisma client +RUN node_modules/.bin/prisma generate + +FROM node:lts-alpine + +RUN apk add --no-cache openssl + +USER node:node + +WORKDIR /app + +COPY --from=build --chown=node:node /app . + EXPOSE 8080 diff --git a/README.md b/README.md index 854146a..2ee653b 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,11 @@ git clone https://github.com/liamcottle/meshtastic-map cd meshtastic-map ``` +Install Meshtastic protobufs definitions +``` +git clone https://github.com/meshtastic/protobufs src/protobufs +``` + Install NodeJS dependencies ``` diff --git a/docker-compose.yml b/docker-compose.yml index 85d17e6..026bb0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,18 @@ services: DATABASE_URL: "mysql://root:password@database:3306/meshtastic-map?connection_limit=100" MAP_OPTS: "" # add any custom index.js options here + # publishes mqtt packets via websocket + meshtastic-ws: + container_name: meshtastic-ws + build: + context: . + dockerfile: ./Dockerfile + command: /app/docker/ws.sh + ports: + - 8081:8081/tcp + environment: + WS_OPTS: "" + # runs the database to store everything from mqtt database: container_name: database diff --git a/docker/ws.sh b/docker/ws.sh new file mode 100755 index 0000000..71d4048 --- /dev/null +++ b/docker/ws.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "Starting websocket publisher" +exec node src/ws.js ${WS_OPTS} + diff --git a/package-lock.json b/package-lock.json index 4d91435..1fb2318 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,37 +9,19 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@prisma/client": "^5.11.0", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.1", - "compression": "^1.7.4", - "express": "^4.18.3", - "mqtt": "^5.3.6", - "protobufjs": "^7.2.6" + "@prisma/client": "^6.16.2", + "command-line-args": "^6.0.1", + "command-line-usage": "^7.0.3", + "compression": "^1.8.1", + "cors": "^2.8.5", + "express": "^5.2.1", + "mqtt": "^5.14.1", + "protobufjs": "^7.5.4", + "ws": "^8.18.3" }, "devDependencies": { - "jest": "^29.7.0", - "prisma": "^5.10.2" - } - }, - "node_modules/@75lb/deep-merge": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", - "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", - "dependencies": { - "lodash.assignwith": "^4.2.0", - "typical": "^7.1.1" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/@75lb/deep-merge/node_modules/typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", - "engines": { - "node": ">=12.17" + "jest": "^30.1.3", + "prisma": "^6.16.2" } }, "node_modules/@ampproject/remapping": { @@ -47,6 +29,7 @@ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -56,43 +39,48 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -108,10 +96,11 @@ } }, "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -128,32 +117,36 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -166,33 +159,45 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -202,160 +207,67 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", - "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.28.2" }, "bin": { "parser": "bin/babel-parser.js" @@ -369,6 +281,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -381,6 +294,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -393,6 +307,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -405,6 +320,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -416,12 +332,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", - "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -435,6 +352,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -447,6 +365,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -455,12 +374,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -474,6 +394,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -486,6 +407,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -498,6 +420,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -510,6 +433,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -522,6 +446,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -534,6 +459,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -546,6 +472,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -561,6 +488,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -572,12 +500,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", - "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -587,53 +516,54 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -650,17 +580,18 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -670,13 +601,67 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -693,64 +678,67 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.1.2.tgz", + "integrity": "sha512-BGMAxj8VRmoD0MoA/jo9alMXSRoqW8KPeqOfEo1ncxnRLatTBCpRoOwlwlEMdudp68Q6WSGwYrrLtTGOh8fLzw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", + "chalk": "^4.1.2", + "jest-message-util": "30.1.0", + "jest-util": "30.0.5", "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.1.3.tgz", + "integrity": "sha512-LIQz7NEDDO1+eyOA2ZmkiAyYvZuo6s1UxD/e2IHldR6D7UYogVq3arTmli07MkENLq6/3JEQjp0mA8rrHHJ8KQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/console": "30.1.2", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.1.3", + "@jest/test-result": "30.1.3", + "@jest/transform": "30.1.2", + "@jest/types": "30.0.5", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.0.5", + "jest-config": "30.1.3", + "jest-haste-map": "30.1.0", + "jest-message-util": "30.1.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.1.3", + "jest-resolve-dependencies": "30.1.3", + "jest-runner": "30.1.3", + "jest-runtime": "30.1.3", + "jest-snapshot": "30.1.2", + "jest-util": "30.0.5", + "jest-validate": "30.1.0", + "jest-watcher": "30.1.3", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -761,111 +749,150 @@ } } }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.1.2.tgz", + "integrity": "sha512-N8t1Ytw4/mr9uN28OnVf0SYE2dGhaIxOVYcwsf9IInBKjvofAjbFRvedvBBlyTYk2knbJTiEjEJ2PyyDIBnd9w==", + "dev": true, + "license": "MIT", "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/fake-timers": "30.1.2", + "@jest/types": "30.0.5", "@types/node": "*", - "jest-mock": "^29.7.0" + "jest-mock": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.1.2.tgz", + "integrity": "sha512-tyaIExOwQRCxPCGNC05lIjWJztDwk2gPDNSDGg1zitXJJ8dC3++G/CRjE5mb2wQsf89+lsgAgqxxNpDLiCViTA==", "dev": true, + "license": "MIT", "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" + "expect": "30.1.2", + "jest-snapshot": "30.1.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.1.2.tgz", + "integrity": "sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A==", "dev": true, + "license": "MIT", "dependencies": { - "jest-get-type": "^29.6.3" + "@jest/get-type": "30.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.1.2.tgz", + "integrity": "sha512-Beljfv9AYkr9K+ETX9tvV61rJTY706BhBUtiaepQHeEGfe0DbpvUA5Z3fomwc5Xkhns6NWrcFDZn+72fLieUnA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", + "@jest/types": "30.0.5", + "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" + "jest-message-util": "30.1.0", + "jest-mock": "30.0.5", + "jest-util": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.1.2.tgz", + "integrity": "sha512-teNTPZ8yZe3ahbYnvnVRDeOjr+3pu2uiAtNtrEsiMjVPPj+cXd5E/fr8BL7v/T7F31vYdEHrI5cC/2OoO/vM9A==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" + "@jest/environment": "30.1.2", + "@jest/expect": "30.1.2", + "@jest/types": "30.0.5", + "jest-mock": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.1.3.tgz", + "integrity": "sha512-VWEQmJWfXMOrzdFEOyGjUEOuVXllgZsoPtEHZzfdNz18RmzJ5nlR6kp8hDdY8dDS1yGOXAY7DHT+AOHIPSBV0w==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", + "@jest/console": "30.1.2", + "@jest/test-result": "30.1.3", + "@jest/transform": "30.1.2", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", + "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", + "jest-message-util": "30.1.0", + "jest-util": "30.0.5", + "jest-worker": "30.1.0", "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", + "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -877,116 +904,136 @@ } }, "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, + "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.1.2.tgz", + "integrity": "sha512-vHoMTpimcPSR7OxS2S0V1Cpg8eKDRxucHjoWl5u4RQcnxqQrV3avETiFpl8etn4dqxEGarBeHbIBety/f8mLXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.1.3.tgz", + "integrity": "sha512-P9IV8T24D43cNRANPPokn7tZh0FAFnYS2HIfi5vK18CjRkTDR9Y3e1BoEcAJnl4ghZZF4Ecda4M/k41QkvurEQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@jest/console": "30.1.2", + "@jest/types": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.1.3.tgz", + "integrity": "sha512-82J+hzC0qeQIiiZDThh+YUadvshdBswi5nuyXlEmXzrhw5ZQSRHeQ5LpVMD/xc8B3wPePvs6VMzHnntxL+4E3w==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", + "@jest/test-result": "30.1.3", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz", + "integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.1.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" + "write-file-atomic": "^5.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz", + "integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -994,95 +1041,149 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@prisma/client": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.16.1.tgz", - "integrity": "sha512-wM9SKQjF0qLxdnOZIVAIMKiz6Hu7vDt4FFAih85K1dk/Rr2mdahy6d3QP41K62N9O0DJJA//gUDA3Mp49xsKIg==", - "hasInstallScript": true, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=16.13" + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz", + "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" }, "peerDependencies": { - "prisma": "*" + "prisma": "*", + "typescript": ">=5.1.0" }, "peerDependenciesMeta": { "prisma": { "optional": true + }, + "typescript": { + "optional": true } } }, + "node_modules/@prisma/config": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.2.tgz", + "integrity": "sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "empathic": "2.0.0" + } + }, "node_modules/@prisma/debug": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.16.1.tgz", - "integrity": "sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==", - "devOptional": true + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz", + "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.16.1.tgz", - "integrity": "sha512-KkyF3eIUtBIyp5A/rJHCtwQO18OjpGgx18PzjyGcJDY/+vNgaVyuVd+TgwBgeq6NLdd1XMwRCI+58vinHsAdfA==", + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.2.tgz", + "integrity": "sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1", - "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "@prisma/fetch-engine": "5.16.1", - "@prisma/get-platform": "5.16.1" + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/fetch-engine": "6.16.2", + "@prisma/get-platform": "6.16.2" } }, "node_modules/@prisma/engines-version": { - "version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303.tgz", - "integrity": "sha512-HkT2WbfmFZ9WUPyuJHhkiADxazHg8Y4gByrTSVeb3OikP6tjQ7txtSUGu9OBOBH0C13dPKN2qqH12xKtHu/Hiw==", - "devOptional": true + "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", + "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.16.1.tgz", - "integrity": "sha512-oOkjaPU1lhcA/Rvr4GVfd1NLJBwExgNBE36Ueq7dr71kTMwy++a3U3oLd2ZwrV9dj9xoP6LjCcky799D9nEt4w==", + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.2.tgz", + "integrity": "sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1", - "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "@prisma/get-platform": "5.16.1" + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/get-platform": "6.16.2" } }, "node_modules/@prisma/get-platform": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.16.1.tgz", - "integrity": "sha512-R4IKnWnMkR2nUAbU5gjrPehdQYUUd7RENFD2/D+xXTNhcqczp0N+WEGQ3ViyI3+6mtVcjjNIMdnUTNyu3GxIgA==", + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.2.tgz", + "integrity": "sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1" + "@prisma/debug": "6.16.2" } }, "node_modules/@protobufjs/aspromise": { @@ -1140,27 +1241,48 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/babel__core": { @@ -1168,6 +1290,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1177,10 +1300,11 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1190,40 +1314,35 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" + "@babel/types": "^7.28.2" } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -1233,6 +1352,7 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -1246,24 +1366,26 @@ } }, "node_modules/@types/readable-stream": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.14.tgz", - "integrity": "sha512-xZn/AuUbCMShGsqH/ehZtGDwQtbx00M9rZ2ENLe4tOjFZ/JFeWMhEZkk2fEe1jAUqqEAURIkFJ7Az/go8mM1/w==", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz", + "integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==", + "license": "MIT", "dependencies": { - "@types/node": "*", - "safe-buffer": "~5.1.1" + "@types/node": "*" } }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1273,6 +1395,7 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1281,12 +1404,290 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -1294,23 +1695,12 @@ "node": ">=6.5" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -1322,12 +1712,16 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", + "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -1349,6 +1743,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1362,96 +1757,80 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=12.17" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.1.2.tgz", + "integrity": "sha512-IQCus1rt9kaSh7PQxLYRY5NmkNrNlU2TpabzwV7T2jljnpdHOcmnYYv8QmE04Li4S3a2Lj8/yXyET5pBarPr6g==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", + "@jest/transform": "30.1.2", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.0", + "babel-preset-jest": "30.0.1", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.8.0" + "@babel/core": "^7.11.0" } }, "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz", + "integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz", + "integrity": "sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", + "@types/babel__core": "^7.20.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -1470,30 +1849,32 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz", + "integrity": "sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==", "dev": true, + "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" + "babel-plugin-jest-hoist": "30.0.1", + "babel-preset-current-node-syntax": "^1.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.11.0" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -1512,12 +1893,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bl": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.13.tgz", - "integrity": "sha512-tMncAcpsyjZgAVbVFupVIaB2xud13xxT59fdHkuszY2jdZkqIWfpQdmII1fOe3kOGAz0mNLTIHEm+KxpYsQKKg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.0.tgz", + "integrity": "sha512-ClDyJGQkc8ZtzdAAbAwBmhMSpwN/sC9HA8jxdYm6nVUbCfZbe2mgza4qh7AuEYyEPB/c4Kznf9s66bnsKMQDjw==", + "license": "MIT", "dependencies": { "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", @@ -1526,44 +1909,60 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/body-parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -1571,6 +1970,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -1578,10 +1978,22 @@ "node": ">=8" } }, + "node_modules/broker-factory": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.8.tgz", + "integrity": "sha512-xmVnYN0FZtynhPUmAnN+/MFRdbDi3syCuxWV7o7s78FcIN0pjDtn9mUrVqEgdjQkbfojRhlPWbYbXJkMCyddrg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "fast-unique-numbers": "^9.0.22", + "tslib": "^2.8.1", + "worker-factory": "^7.0.44" + } + }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", + "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", "dev": true, "funding": [ { @@ -1597,11 +2009,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", + "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "caniuse-lite": "^1.0.30001737", + "electron-to-chromium": "^1.5.211", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -1615,6 +2029,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -1637,6 +2052,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -1648,23 +2064,64 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -1678,6 +2135,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1687,14 +2145,15 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001664", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz", - "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==", + "version": "1.0.30001739", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz", + "integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==", "dev": true, "funding": [ { @@ -1709,7 +2168,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "4.1.2", @@ -1745,14 +2205,31 @@ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", "dev": true, "funding": [ { @@ -1760,21 +2237,34 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/cjs-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", - "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", + "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "dev": true, + "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1784,11 +2274,75 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -1798,7 +2352,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", @@ -1817,53 +2372,48 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", + "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", + "license": "MIT", "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", + "array-back": "^6.2.2", + "find-replace": "^5.0.2", "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "typical": "^7.2.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=12.20" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/command-line-usage": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", - "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "license": "MIT", "dependencies": { "array-back": "^6.2.2", "chalk-template": "^0.4.0", - "table-layout": "^3.0.0", + "table-layout": "^4.1.0", "typical": "^7.1.1" }, "engines": { "node": ">=12.20.0" } }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", - "engines": { - "node": ">=12.17" - } - }, "node_modules/commist": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", - "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==" + "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==", + "license": "MIT" }, "node_modules/compressible": { "version": "2.0.18", @@ -1877,16 +2427,17 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { @@ -1897,7 +2448,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-stream": { "version": "2.0.0", @@ -1906,6 +2458,7 @@ "engines": [ "node >= 6.0" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -1917,6 +2470,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1926,10 +2480,27 @@ "node": ">= 6" } }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "dependencies": { "safe-buffer": "5.2.1" }, @@ -1937,29 +2508,11 @@ "node": ">= 0.6" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "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" } @@ -1968,47 +2521,43 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "engines": { + "node": ">=6.6.0" + } }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" + "object-assign": "^4", + "vary": "^1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.10" } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2027,10 +2576,11 @@ } }, "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -2045,26 +2595,28 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=16.0.0" } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2073,49 +2625,86 @@ "node": ">= 0.8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, "node_modules/electron-to-chromium": { - "version": "1.5.30", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.30.tgz", - "integrity": "sha512-sXI35EBN4lYxzc/pIGorlymYNzDBOqkSlVRe6MkgBsW/hW1tpC/HDJ2fjG7XnjakzfLEuvdmux0Mjs6jHq4UOA==", - "dev": true + "version": "1.5.212", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.212.tgz", + "integrity": "sha512-gE7ErIzSW+d8jALWMcOIgf+IB6lpfsg6NwOhPVwKzDtN2qcBix47vlin4yzSregYDxTCXOUqAZjVY/Z3naS7ww==", + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2124,15 +2713,26 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -2142,17 +2742,16 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2161,6 +2760,19 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, "engines": { "node": ">= 0.4" } @@ -2170,6 +2782,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2184,6 +2797,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2193,6 +2807,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2213,6 +2828,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2221,6 +2837,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -2230,6 +2847,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -2248,107 +2866,190 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.1.2.tgz", + "integrity": "sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" + "@jest/expect-utils": "30.1.2", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.1.2", + "jest-message-util": "30.1.0", + "jest-mock": "30.0.5", + "jest-util": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/express/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/express/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "type": "opencollective", + "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-check/node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-unique-numbers": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz", - "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==", + "version": "9.0.22", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.22.tgz", + "integrity": "sha512-dBR+30yHAqBGvOuxxQdnn2lTLHCO6r/9B+M4yF8mNrzr3u1yiF+YVJ6u3GTyPN/VRWqaE1FcscZDdBgVKmrmQQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.8", - "tslib": "^2.6.2" + "@babel/runtime": "^7.27.6", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.1.0" + "node": ">=18.2.0" } }, "node_modules/fb-watchman": { @@ -2356,6 +3057,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -2365,6 +3067,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2373,31 +3076,57 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { "node": ">= 0.8" } }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "node_modules/finalhandler/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dependencies": { - "array-back": "^3.0.1" + "ms": "^2.1.3" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/find-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", + "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/find-up": { @@ -2405,6 +3134,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -2413,6 +3143,23 @@ "node": ">=8" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2422,18 +3169,19 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -2441,6 +3189,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2453,6 +3202,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2462,6 +3212,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -2471,20 +3222,27 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2498,15 +3256,30 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2514,42 +3287,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" }, - "engines": { - "node": "*" + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2559,7 +3342,8 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", @@ -2569,32 +3353,11 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2606,6 +3369,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2616,27 +3380,34 @@ "node_modules/help-me": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/human-signals": { @@ -2644,19 +3415,25 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ieee754": { @@ -2676,13 +3453,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -2702,6 +3481,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -2712,6 +3492,7 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2722,6 +3503,25 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2734,28 +3534,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2765,6 +3552,7 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2774,15 +3562,22 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2794,13 +3589,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -2810,6 +3607,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -2822,10 +3620,11 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2838,6 +3637,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -2848,24 +3648,26 @@ } }, "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "istanbul-lib-coverage": "^3.0.0" }, "engines": { "node": ">=10" } }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2882,13 +3684,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -2897,22 +3701,39 @@ "node": ">=8" } }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.1.3.tgz", + "integrity": "sha512-Ry+p2+NLk6u8Agh5yVqELfUJvRfV51hhVBRIB5yZPY7mU0DGBmOuFG5GebZbMbm86cdQNK0fhJuDX8/1YorISQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.1.3", + "@jest/types": "30.0.5", + "import-local": "^3.2.0", + "jest-cli": "30.1.3" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -2924,73 +3745,75 @@ } }, "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.0.5.tgz", + "integrity": "sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==", "dev": true, + "license": "MIT", "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", + "execa": "^5.1.1", + "jest-util": "30.0.5", "p-limit": "^3.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.1.3.tgz", + "integrity": "sha512-Yf3dnhRON2GJT4RYzM89t/EXIWNxKTpWTL9BfF3+geFetWP4XSvJjiU1vrWplOiUkmq8cHLiwuhz+XuUp9DscA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/environment": "30.1.2", + "@jest/expect": "30.1.2", + "@jest/test-result": "30.1.3", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", + "chalk": "^4.1.2", "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.1.0", + "jest-matcher-utils": "30.1.2", + "jest-message-util": "30.1.0", + "jest-runtime": "30.1.3", + "jest-snapshot": "30.1.2", + "jest-util": "30.0.5", "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", + "pretty-format": "30.0.5", + "pure-rand": "^7.0.0", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.6" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.1.3.tgz", + "integrity": "sha512-G8E2Ol3OKch1DEeIBl41NP7OiC6LBhfg25Btv+idcusmoUSpqUkbrneMqbW9lVpI/rCKb/uETidb7DNteheuAQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" + "@jest/core": "30.1.3", + "@jest/test-result": "30.1.3", + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.1.3", + "jest-util": "30.0.5", + "jest-validate": "30.1.0", + "yargs": "^17.7.2" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -3002,204 +3825,211 @@ } }, "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.1.3.tgz", + "integrity": "sha512-M/f7gqdQEPgZNA181Myz+GXCe8jXcJsGjCMXUzRj22FIXsZOyHNte84e0exntOvdPaeh9tA0w+B8qlP2fAezfw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.1.3", + "@jest/types": "30.0.5", + "babel-jest": "30.1.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.1.3", + "jest-docblock": "30.0.1", + "jest-environment-node": "30.1.2", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.1.3", + "jest-runner": "30.1.3", + "jest-util": "30.0.5", + "jest-validate": "30.1.0", + "micromatch": "^4.0.8", "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", + "pretty-format": "30.0.5", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { "@types/node": "*", + "esbuild-register": ">=3.4.0", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "esbuild-register": { + "optional": true + }, "ts-node": { "optional": true } } }, "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz", + "integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.0.1.tgz", + "integrity": "sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==", "dev": true, + "license": "MIT", "dependencies": { - "detect-newline": "^3.0.0" + "detect-newline": "^3.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.1.0.tgz", + "integrity": "sha512-A+9FKzxPluqogNahpCv04UJvcZ9B3HamqpDNWNKDjtxVRYB8xbZLFuCr8JAJFpNp83CA0anGQFlpQna9Me+/tQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" + "@jest/get-type": "30.1.0", + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "jest-util": "30.0.5", + "pretty-format": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.1.2.tgz", + "integrity": "sha512-w8qBiXtqGWJ9xpJIA98M0EIoq079GOQRQUyse5qg1plShUCQ0Ek1VTTcczqKrn3f24TFAgFtT+4q3aOXvjbsuA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/environment": "30.1.2", + "@jest/fake-timers": "30.1.2", + "@jest/types": "30.0.5", "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" + "jest-mock": "30.0.5", + "jest-util": "30.0.5", + "jest-validate": "30.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz", + "integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", + "@jest/types": "30.0.5", "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.1.0", + "micromatch": "^4.0.8", "walker": "^1.0.8" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "optionalDependencies": { - "fsevents": "^2.3.2" + "fsevents": "^2.3.3" } }, "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.1.0.tgz", + "integrity": "sha512-AoFvJzwxK+4KohH60vRuHaqXfWmeBATFZpzpmzNmYTtmRMiyGPVhkXpBqxUQunw+dQB48bDf4NpUs6ivVbRv1g==", "dev": true, + "license": "MIT", "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jest/get-type": "30.1.0", + "pretty-format": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.1.2.tgz", + "integrity": "sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.1.2", + "pretty-format": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz", + "integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.6" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.5.tgz", + "integrity": "sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", + "@jest/types": "30.0.5", "@types/node": "*", - "jest-util": "^29.7.0" + "jest-util": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-pnp-resolver": { @@ -3207,6 +4037,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -3220,148 +4051,156 @@ } }, "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", "dev": true, + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.1.3.tgz", + "integrity": "sha512-DI4PtTqzw9GwELFS41sdMK32Ajp3XZQ8iygeDMWkxlRhm7uUTOFSZFVZABFuxr0jvspn8MAYy54NxZCsuCTSOw==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.1.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.0.5", + "jest-validate": "30.1.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.1.3.tgz", + "integrity": "sha512-DNfq3WGmuRyHRHfEet+Zm3QOmVFtIarUOQHHryKPc0YL9ROfgWZxl4+aZq/VAzok2SS3gZdniP+dO4zgo59hBg==", "dev": true, + "license": "MIT", "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.1.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.1.3.tgz", + "integrity": "sha512-dd1ORcxQraW44Uz029TtXj85W11yvLpDuIzNOlofrC8GN+SgDlgY4BvyxJiVeuabA1t6idjNbX59jLd2oplOGQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/console": "30.1.2", + "@jest/environment": "30.1.2", + "@jest/test-result": "30.1.3", + "@jest/transform": "30.1.2", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", + "chalk": "^4.1.2", "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.0.1", + "jest-environment-node": "30.1.2", + "jest-haste-map": "30.1.0", + "jest-leak-detector": "30.1.0", + "jest-message-util": "30.1.0", + "jest-resolve": "30.1.3", + "jest-runtime": "30.1.3", + "jest-util": "30.0.5", + "jest-watcher": "30.1.3", + "jest-worker": "30.1.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.1.3.tgz", + "integrity": "sha512-WS8xgjuNSphdIGnleQcJ3AKE4tBKOVP+tKhCD0u+Tb2sBmsU8DxfbBpZX7//+XOz81zVs4eFpJQwBNji2Y07DA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/environment": "30.1.2", + "@jest/fake-timers": "30.1.2", + "@jest/globals": "30.1.2", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.1.3", + "@jest/transform": "30.1.2", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.1.0", + "jest-message-util": "30.1.0", + "jest-mock": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.1.3", + "jest-snapshot": "30.1.2", + "jest-util": "30.0.5", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.1.2.tgz", + "integrity": "sha512-4q4+6+1c8B6Cy5pGgFvjDy/Pa6VYRiGu0yQafKkJ9u6wQx4G5PqI2QR6nxTl43yy7IWsINwz6oT4o6tD12a8Dg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.1.2", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.1.2", + "@jest/transform": "30.1.2", + "@jest/types": "30.0.5", + "babel-preset-current-node-syntax": "^1.1.0", + "chalk": "^4.1.2", + "expect": "30.1.2", + "graceful-fs": "^4.2.11", + "jest-diff": "30.1.2", + "jest-matcher-utils": "30.1.2", + "jest-message-util": "30.1.0", + "jest-util": "30.0.5", + "pretty-format": "30.0.5", + "semver": "^7.7.2", + "synckit": "^0.11.8" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3370,37 +4209,52 @@ } }, "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.1.0.tgz", + "integrity": "sha512-7P3ZlCFW/vhfQ8pE7zW6Oi4EzvuB4sgR72Q1INfW9m0FGo0GADYlPwIkf4CyPq7wq85g+kPMtPOHNAdWHeBOaA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", + "@jest/get-type": "30.1.0", + "@jest/types": "30.0.5", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "pretty-format": "30.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-validate/node_modules/camelcase": { @@ -3408,6 +4262,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3416,37 +4271,40 @@ } }, "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "version": "30.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.1.3.tgz", + "integrity": "sha512-6jQUZCP1BTL2gvG9E4YF06Ytq4yMb4If6YoQGRR6PpjtqOXSP3sKe2kqwB6SQ+H9DezOfZaSLnmka1NtGm3fCQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/test-result": "30.1.3", + "@jest/types": "30.0.5", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" + "jest-util": "30.0.5", + "string-length": "^4.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.1.0.tgz", + "integrity": "sha512-uvWcSjlwAAgIu133Tt77A05H7RIk3Ho8tZL50bQM2AkvLdluw9NG48lRCl3Dt+MOH719n/0nnb5YxUwcuJiKRA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", - "jest-util": "^29.7.0", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "supports-color": "^8.1.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-worker/node_modules/supports-color": { @@ -3454,6 +4312,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3464,10 +4323,21 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" @@ -3477,13 +4347,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3492,29 +4364,38 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -3522,20 +4403,12 @@ "node": ">=6" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3544,13 +4417,15 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -3558,11 +4433,6 @@ "node": ">=8" } }, - "node_modules/lodash.assignwith": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -3574,18 +4444,17 @@ "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, "node_modules/lru-cache": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", - "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", - "engines": { - "node": "14 || >=16.14" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -3597,10 +4466,11 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3613,42 +4483,53 @@ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } + "dev": true, + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -3657,34 +4538,29 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-fn": { @@ -3692,52 +4568,68 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mqtt": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.7.3.tgz", - "integrity": "sha512-v+5la6Q6zjl0AWsI7ICDA/K3hclkNj7CMa0khMugCC+LKPLrQF+sSQb/9ckezZLMvcBC1tXhRzqmcagQoDl9fQ==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.14.1.tgz", + "integrity": "sha512-NxkPxE70Uq3Ph7goefQa7ggSsVzHrayCD0OyxlJgITN/EbzlZN+JEPmaAZdxP1LsIT5FamDyILoQTF72W7Nnbw==", + "license": "MIT", "dependencies": { - "@types/readable-stream": "^4.0.5", - "@types/ws": "^8.5.9", + "@types/readable-stream": "^4.0.21", + "@types/ws": "^8.18.1", "commist": "^3.2.0", "concat-stream": "^2.0.0", - "debug": "^4.3.4", + "debug": "^4.4.1", "help-me": "^5.0.0", - "lru-cache": "^10.0.1", + "lru-cache": "^10.4.3", "minimist": "^1.2.8", - "mqtt": "^5.2.0", - "mqtt-packet": "^9.0.0", + "mqtt-packet": "^9.0.2", "number-allocator": "^1.0.14", - "readable-stream": "^4.4.2", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", + "readable-stream": "^4.7.0", + "rfdc": "^1.4.1", + "socks": "^2.8.6", "split2": "^4.2.0", - "worker-timers": "^7.1.4", - "ws": "^8.17.1" + "worker-timers": "^8.0.23", + "ws": "^8.18.3" }, "bin": { "mqtt": "build/bin/mqtt.js", @@ -3749,9 +4641,10 @@ } }, "node_modules/mqtt-packet": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.0.tgz", - "integrity": "sha512-8v+HkX+fwbodsWAZIZTI074XIoxVBOmPeggQuDFCGg1SqNcC+uoRMWu7J6QlJPqIUIJXmjNYYHxBBLr1Y/Df4w==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz", + "integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==", + "license": "MIT", "dependencies": { "bl": "^6.0.8", "debug": "^4.3.4", @@ -3759,11 +4652,12 @@ } }, "node_modules/mqtt-packet/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3775,16 +4669,18 @@ } }, "node_modules/mqtt-packet/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/mqtt/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3796,46 +4692,75 @@ } }, "node_modules/mqtt/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/napi-postinstall": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", + "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "devOptional": true, + "license": "MIT" + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3845,6 +4770,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -3856,17 +4782,19 @@ "version": "1.0.14", "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", + "license": "MIT", "dependencies": { "debug": "^4.3.1", "js-sdsl": "4.3.0" } }, "node_modules/number-allocator/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3878,14 +4806,44 @@ } }, "node_modules/number-allocator/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3893,6 +4851,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -3905,9 +4870,10 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3916,7 +4882,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -3926,6 +4891,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -3941,6 +4907,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -3956,6 +4923,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -3968,6 +4936,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -3983,15 +4952,24 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -4018,6 +4996,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4027,6 +5006,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4036,32 +5016,63 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -4070,10 +5081,11 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -4083,6 +5095,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -4090,18 +5103,31 @@ "node": ">=8" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -4109,6 +5135,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4117,25 +5144,37 @@ } }, "node_modules/prisma": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.16.1.tgz", - "integrity": "sha512-Z1Uqodk44diztImxALgJJfNl2Uisl9xDRvqybMKEBYJLNKNhDfAHf+ZIJbZyYiBhLMbKU9cYGdDVG5IIXEnL2Q==", + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz", + "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@prisma/engines": "5.16.1" + "@prisma/config": "6.16.2", + "@prisma/engines": "6.16.2" }, "bin": { "prisma": "build/index.js" }, "engines": { - "node": ">=16.13" + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -4143,26 +5182,15 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -4194,9 +5222,9 @@ } }, "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", "dev": true, "funding": [ { @@ -4207,14 +5235,16 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -4232,37 +5262,43 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" } }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -4274,47 +5310,36 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/reinterval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", - "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -4327,235 +5352,54 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" } }, - "node_modules/send/node_modules/ms": { + "node_modules/router/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stream-read-all": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", - "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==", - "engines": { - "node": ">=10" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", @@ -4572,13 +5416,301 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/send/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz", + "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -4587,11 +5719,54 @@ "node": ">=10" } }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -4601,11 +5776,29 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4613,11 +5806,52 @@ "node": ">=8" } }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4627,6 +5861,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4636,6 +5871,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4654,50 +5890,31 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, "engines": { - "node": ">= 0.4" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/synckit" } }, "node_modules/table-layout": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", - "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "license": "MIT", "dependencies": { - "@75lb/deep-merge": "^1.1.1", "array-back": "^6.2.2", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.0", - "stream-read-all": "^3.0.1", - "typical": "^7.1.1", "wordwrapjs": "^5.1.0" }, - "bin": { - "table-layout": "bin/cli.js" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", "engines": { "node": ">=12.17" } @@ -4707,6 +5924,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -4716,26 +5934,72 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -4752,15 +6016,17 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -4770,6 +6036,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -4778,12 +6045,14 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" @@ -4792,14 +6061,16 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" }, "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.17" } }, "node_modules/undici-types": { @@ -4811,14 +6082,50 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -4834,9 +6141,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -4848,21 +6156,15 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -4885,6 +6187,7 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -4894,6 +6197,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4908,46 +6212,83 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", + "license": "MIT", "engines": { "node": ">=12.17" } }, - "node_modules/worker-timers": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz", - "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==", + "node_modules/worker-factory": { + "version": "7.0.44", + "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.44.tgz", + "integrity": "sha512-08AuUfWi+KeZI+KC7nU4pU/9tDeAFvE5NSWk+K9nIfuQc6UlOsZtjjeGVYVEn+DEchyXNJ5i10HCn0xRzFXEQA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.24.5", - "tslib": "^2.6.2", - "worker-timers-broker": "^6.1.8", - "worker-timers-worker": "^7.0.71" + "@babel/runtime": "^7.27.6", + "fast-unique-numbers": "^9.0.22", + "tslib": "^2.8.1" + } + }, + "node_modules/worker-timers": { + "version": "8.0.23", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.23.tgz", + "integrity": "sha512-1BnWHNNiu5YEutgF7eVZEqNntAsij2oG0r66xDdScoY3fKGFrok2y0xA8OgG6FA+3srrmAplSY6JN5h9jV5D0w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "tslib": "^2.8.1", + "worker-timers-broker": "^8.0.9", + "worker-timers-worker": "^9.0.9" } }, "node_modules/worker-timers-broker": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz", - "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.9.tgz", + "integrity": "sha512-WJsd7aIvu2GBTXp7IBGT1NKnt3ZbiJ2wqb7Pl4nFJXC8pek84+X68TJGVvvrqwHgHPNxSlzpU1nadhcW4PDD7A==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.24.5", - "fast-unique-numbers": "^8.0.13", - "tslib": "^2.6.2", - "worker-timers-worker": "^7.0.71" + "@babel/runtime": "^7.27.6", + "broker-factory": "^3.1.8", + "fast-unique-numbers": "^9.0.22", + "tslib": "^2.8.1", + "worker-timers-worker": "^9.0.9" } }, "node_modules/worker-timers-worker": { - "version": "7.0.71", - "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz", - "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.9.tgz", + "integrity": "sha512-OOKTMdHbzx7FaXCW40RS8RxAqLF/R8xU5/YA7CFasDy+jBA5yQWUusSQJUFFTV2Z9ZOpnR+ZWgte/IuAqOAEVw==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.24.5", - "tslib": "^2.6.2" + "@babel/runtime": "^7.27.6", + "tslib": "^2.8.1", + "worker-factory": "^7.0.44" } }, "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4960,29 +6301,88 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -5004,6 +6404,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -5012,13 +6413,15 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -5037,15 +6440,62 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 1da346b..989093f 100644 --- a/package.json +++ b/package.json @@ -9,16 +9,18 @@ "author": "", "license": "ISC", "dependencies": { - "@prisma/client": "^5.11.0", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.1", - "compression": "^1.7.4", - "express": "^4.18.3", - "mqtt": "^5.3.6", - "protobufjs": "^7.2.6" + "@prisma/client": "^6.16.2", + "command-line-args": "^6.0.1", + "command-line-usage": "^7.0.3", + "compression": "^1.8.1", + "cors": "^2.8.5", + "express": "^5.2.1", + "mqtt": "^5.14.1", + "protobufjs": "^7.5.4", + "ws": "^8.18.3" }, "devDependencies": { - "jest": "^29.7.0", - "prisma": "^5.10.2" + "jest": "^30.1.3", + "prisma": "^6.16.2" } } diff --git a/prisma/migrations/20250328205405_add_ok_to_mqtt_to_node/migration.sql b/prisma/migrations/20250328205405_add_ok_to_mqtt_to_node/migration.sql new file mode 100644 index 0000000..9bd381c --- /dev/null +++ b/prisma/migrations/20250328205405_add_ok_to_mqtt_to_node/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `nodes` ADD COLUMN `ok_to_mqtt` BOOLEAN NULL; diff --git a/prisma/migrations/20250415153323_add_portnum_to_service_envelopes/migration.sql b/prisma/migrations/20250415153323_add_portnum_to_service_envelopes/migration.sql new file mode 100644 index 0000000..20c56fe --- /dev/null +++ b/prisma/migrations/20250415153323_add_portnum_to_service_envelopes/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `service_envelopes` ADD COLUMN `portnum` INTEGER NULL; diff --git a/prisma/migrations/20250415184546_add_packet_id_to_service_envelopes/migration.sql b/prisma/migrations/20250415184546_add_packet_id_to_service_envelopes/migration.sql new file mode 100644 index 0000000..e0139d5 --- /dev/null +++ b/prisma/migrations/20250415184546_add_packet_id_to_service_envelopes/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `service_envelopes` ADD COLUMN `packet_id` BIGINT NULL; + +-- CreateIndex +CREATE INDEX `service_envelopes_packet_id_idx` ON `service_envelopes`(`packet_id`); diff --git a/prisma/migrations/20250422203347_add_battery_and_channel_util_stats/migration.sql b/prisma/migrations/20250422203347_add_battery_and_channel_util_stats/migration.sql new file mode 100644 index 0000000..1bd67b5 --- /dev/null +++ b/prisma/migrations/20250422203347_add_battery_and_channel_util_stats/migration.sql @@ -0,0 +1,19 @@ +-- CreateTable +CREATE TABLE `battery_stats` ( + `id` BIGINT NOT NULL AUTO_INCREMENT, + `recorded_at` DATETIME(3) NULL DEFAULT CURRENT_TIMESTAMP(3), + `avg_battery_level` DECIMAL(5, 2) NULL, + + INDEX `battery_stats_recorded_at_idx`(`recorded_at`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `channel_utilization_stats` ( + `id` BIGINT NOT NULL AUTO_INCREMENT, + `recorded_at` DATETIME(3) NULL DEFAULT CURRENT_TIMESTAMP(3), + `avg_channel_utilization` DECIMAL(65, 30) NULL, + + INDEX `channel_utilization_stats_recorded_at_idx`(`recorded_at`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/migrations/20250426153224_add_node_name_history/migration.sql b/prisma/migrations/20250426153224_add_node_name_history/migration.sql new file mode 100644 index 0000000..b79e839 --- /dev/null +++ b/prisma/migrations/20250426153224_add_node_name_history/migration.sql @@ -0,0 +1,16 @@ +-- CreateTable +CREATE TABLE `name_history` ( + `id` BIGINT NOT NULL AUTO_INCREMENT, + `node_id` BIGINT NOT NULL, + `long_name` VARCHAR(191) NOT NULL, + `short_name` VARCHAR(191) NOT NULL, + `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + + INDEX `name_history_node_id_idx`(`node_id`), + INDEX `name_history_long_name_idx`(`long_name`), + INDEX `name_history_created_at_idx`(`created_at`), + INDEX `name_history_updated_at_idx`(`updated_at`), + UNIQUE INDEX `name_history_node_id_long_name_short_name_key`(`node_id`, `long_name`, `short_name`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/migrations/20250627090409_add_node_is_backbone/migration.sql b/prisma/migrations/20250627090409_add_node_is_backbone/migration.sql new file mode 100644 index 0000000..e449774 --- /dev/null +++ b/prisma/migrations/20250627090409_add_node_is_backbone/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `nodes` ADD COLUMN `is_backbone` BOOLEAN NULL; diff --git a/prisma/migrations/20250805210540_add_node_pulickey_and_unmessagable/migration.sql b/prisma/migrations/20250805210540_add_node_pulickey_and_unmessagable/migration.sql new file mode 100644 index 0000000..5c2e5ac --- /dev/null +++ b/prisma/migrations/20250805210540_add_node_pulickey_and_unmessagable/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE `nodes` ADD COLUMN `is_unmessagable` BOOLEAN NULL, + ADD COLUMN `public_key` VARCHAR(191) NULL; diff --git a/prisma/migrations/20250810082255_add_node_max_hops/migration.sql b/prisma/migrations/20250810082255_add_node_max_hops/migration.sql new file mode 100644 index 0000000..b9dc9b4 --- /dev/null +++ b/prisma/migrations/20250810082255_add_node_max_hops/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `nodes` ADD COLUMN `max_hops` INTEGER NULL; diff --git a/prisma/migrations/20250813193012_add_node_channel_id/migration.sql b/prisma/migrations/20250813193012_add_node_channel_id/migration.sql new file mode 100644 index 0000000..9498fea --- /dev/null +++ b/prisma/migrations/20250813193012_add_node_channel_id/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `nodes` ADD COLUMN `channel_id` VARCHAR(191) NULL; diff --git a/prisma/migrations/20250925171652_add_chutil_channel_id/migration.sql b/prisma/migrations/20250925171652_add_chutil_channel_id/migration.sql new file mode 100644 index 0000000..771f018 --- /dev/null +++ b/prisma/migrations/20250925171652_add_chutil_channel_id/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `channel_utilization_stats` ADD COLUMN `channel_id` VARCHAR(191) NULL; + +-- CreateIndex +CREATE INDEX `channel_utilization_stats_channel_id_idx` ON `channel_utilization_stats`(`channel_id`); diff --git a/prisma/migrations/20250929184048_add_ok_to_mqtt_to_text_messages/migration.sql b/prisma/migrations/20250929184048_add_ok_to_mqtt_to_text_messages/migration.sql new file mode 100644 index 0000000..5a14c0c --- /dev/null +++ b/prisma/migrations/20250929184048_add_ok_to_mqtt_to_text_messages/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `text_messages` ADD COLUMN `ok_to_mqtt` BOOLEAN NULL; diff --git a/prisma/migrations/20260106151912_add_edges/migration.sql b/prisma/migrations/20260106151912_add_edges/migration.sql new file mode 100644 index 0000000..113243f --- /dev/null +++ b/prisma/migrations/20260106151912_add_edges/migration.sql @@ -0,0 +1,23 @@ +-- CreateTable +CREATE TABLE `edges` ( + `id` BIGINT NOT NULL AUTO_INCREMENT, + `from_node_id` BIGINT NOT NULL, + `to_node_id` BIGINT NOT NULL, + `snr` INTEGER NOT NULL, + `from_latitude` INTEGER NULL, + `from_longitude` INTEGER NULL, + `to_latitude` INTEGER NULL, + `to_longitude` INTEGER NULL, + `packet_id` BIGINT NOT NULL, + `channel_id` VARCHAR(191) NULL, + `gateway_id` BIGINT NULL, + `source` VARCHAR(191) NOT NULL, + `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + + INDEX `edges_from_node_id_idx`(`from_node_id`), + INDEX `edges_to_node_id_idx`(`to_node_id`), + INDEX `edges_created_at_idx`(`created_at`), + INDEX `edges_from_node_id_to_node_id_idx`(`from_node_id`, `to_node_id`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6741657..2a908dc 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -21,6 +21,8 @@ model Node { hardware_model Int role Int is_licensed Boolean? + public_key String? + is_unmessagable Boolean? firmware_version String? region Int? @@ -51,6 +53,12 @@ model Node { // this column tracks when an mqtt gateway node uplinked a packet mqtt_connection_state_updated_at DateTime? + ok_to_mqtt Boolean? + is_backbone Boolean? + max_hops Int? + + channel_id String? + created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt @@ -202,6 +210,8 @@ model ServiceEnvelope { gateway_id BigInt? to BigInt from BigInt + portnum Int? + packet_id BigInt? protobuf Bytes created_at DateTime @default(now()) @@ -210,6 +220,7 @@ model ServiceEnvelope { @@index(created_at) @@index(updated_at) @@index(gateway_id) + @@index(packet_id) @@map("service_envelopes") } @@ -228,6 +239,7 @@ model TextMessage { rx_snr Decimal? rx_rssi Int? hop_limit Int? + ok_to_mqtt Boolean? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt @@ -296,3 +308,67 @@ model Waypoint { @@index(gateway_id) @@map("waypoints") } + +model NameHistory { + id BigInt @id @default(autoincrement()) + node_id BigInt + long_name String + short_name String + + created_at DateTime @default(now()) + updated_at DateTime @default(now()) @updatedAt + + @@index(node_id) + @@index(long_name) + + @@index(created_at) + @@index(updated_at) + @@map("name_history") + + // We only want to keep track of unique name and node_id combinations + @@unique([node_id, long_name, short_name]) +} + +model BatteryStats { + id BigInt @id @default(autoincrement()) + recorded_at DateTime? @default(now()) + avg_battery_level Decimal? @db.Decimal(5, 2) + + @@index([recorded_at]) + @@map("battery_stats") +} + +model ChannelUtilizationStats { + id BigInt @id @default(autoincrement()) + recorded_at DateTime? @default(now()) + avg_channel_utilization Decimal? + channel_id String? + + @@index([channel_id]) + @@index([recorded_at]) + @@map("channel_utilization_stats") +} + +model Edge { + id BigInt @id @default(autoincrement()) + from_node_id BigInt + to_node_id BigInt + snr Int + from_latitude Int? + from_longitude Int? + to_latitude Int? + to_longitude Int? + packet_id BigInt + channel_id String? + gateway_id BigInt? + source String + + created_at DateTime @default(now()) + updated_at DateTime @default(now()) @updatedAt + + @@index(from_node_id) + @@index(to_node_id) + @@index(created_at) + @@index([from_node_id, to_node_id]) + @@map("edges") +} \ No newline at end of file diff --git a/screenshot.png b/screenshot.png index 13d17b2..25ee627 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/src/admin.js b/src/admin.js index e9fbbef..5889908 100644 --- a/src/admin.js +++ b/src/admin.js @@ -1,6 +1,7 @@ // node src/admin.js --purge-node-id 123 // node src/admin.js --purge-node-id '!AABBCCDD' +require('./utils/logger'); const commandLineArgs = require("command-line-args"); const commandLineUsage = require("command-line-usage"); diff --git a/src/index.js b/src/index.js index 61bd055..48dbcc2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,13 @@ +require('./utils/logger'); const path = require('path'); const express = require('express'); const compression = require('compression'); const protobufjs = require("protobufjs"); const commandLineArgs = require("command-line-args"); const commandLineUsage = require("command-line-usage"); +const cors = require('cors'); + +const statsRoutes = require('./stats.js'); // create prisma db client const { PrismaClient } = require("@prisma/client"); @@ -52,7 +56,7 @@ const port = options["port"] ?? 8080; // load protobufs const root = new protobufjs.Root(); -root.resolvePath = (origin, target) => path.join(__dirname, "protos", target); +root.resolvePath = (origin, target) => path.join(__dirname, "protobufs", target); root.loadSync('meshtastic/mqtt.proto'); const HardwareModel = root.lookupEnum("HardwareModel"); const Role = root.lookupEnum("Config.DeviceConfig.Role"); @@ -76,6 +80,9 @@ const app = express(); // enable compression app.use(compression()); +// Apply CORS only to API routes +app.use('/api', cors()); + // serve files inside the public folder from / app.use('/', express.static(path.join(__dirname, 'public'))); @@ -83,6 +90,9 @@ app.get('/', async (req, res) => { res.sendFile(path.join(__dirname, 'public/index.html')); }); +// stats API in separate file +app.use('/api/v1/stats', statsRoutes); + app.get('/api', async (req, res) => { const links = [ @@ -137,6 +147,23 @@ app.get('/api', async (req, res) => { "path": "/api/v1/nodes/:nodeId/traceroutes", "description": "Trace routes for a meshtastic node", }, + { + "path": "/api/v1/traceroutes", + "description": "Recent traceroute edges across all nodes", + "params": { + "time_from": "Only include traceroutes updated after this unix timestamp (milliseconds)", + "time_to": "Only include traceroutes updated before this unix timestamp (milliseconds)" + } + }, + { + "path": "/api/v1/connections", + "description": "Aggregated edges between nodes from traceroutes", + "params": { + "node_id": "Only include connections involving this node id", + "time_from": "Only include edges created after this unix timestamp (milliseconds)", + "time_to": "Only include edges created before this unix timestamp (milliseconds)" + } + }, { "path": "/api/v1/nodes/:nodeId/position-history", "description": "Position history for a meshtastic node", @@ -202,6 +229,10 @@ app.get('/api/v1/nodes', async (req, res) => { where: { role: role, hardware_model: hardwareModel, + // Since we removed retention; only include nodes that have been updated in the last 30 days + updated_at: { + gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) // within last 30 days + } }, }); @@ -557,6 +588,313 @@ app.get('/api/v1/nodes/:nodeId/traceroutes', async (req, res) => { } }); +// Aggregated recent traceroute edges (global), filtered by updated_at +// Returns deduplicated edges with the latest SNR and timestamp. +// GET /api/v1/nodes/traceroutes?time_from=...&time_to=... +app.get('/api/v1/traceroutes', async (req, res) => { + try { + + const timeFrom = req.query.time_from ? parseInt(req.query.time_from) : undefined; + const timeTo = req.query.time_to ? parseInt(req.query.time_to) : undefined; + + // Pull recent traceroutes within the time window. We only want replies (want_response=false) + // and those that were actually gated to MQTT (gateway_id not null) + const traces = await prisma.traceRoute.findMany({ + where: { + want_response: false, + gateway_id: { not: null }, + updated_at: { + gte: timeFrom ? new Date(timeFrom) : undefined, + lte: timeTo ? new Date(timeTo) : undefined, + }, + }, + orderBy: { id: 'desc' }, + take: 5000, // cap to keep response bounded; UI can page/adjust time window if needed + }); + + // Normalize JSON fields that may be strings (depending on driver) + const normalized = traces.map((t) => { + const trace = { ...t }; + if (typeof trace.route === 'string') { + try { trace.route = JSON.parse(trace.route); } catch(_) {} + } + if (typeof trace.route_back === 'string') { + try { trace.route_back = JSON.parse(trace.route_back); } catch(_) {} + } + if (typeof trace.snr_towards === 'string') { + try { trace.snr_towards = JSON.parse(trace.snr_towards); } catch(_) {} + } + if (typeof trace.snr_back === 'string') { + try { trace.snr_back = JSON.parse(trace.snr_back); } catch(_) {} + } + return trace; + }); + + // Build edges from both forward (towards) and reverse (back) paths. + // Forward path: to → route[] → from, using snr_towards + // Reverse path: from → route_back[] → to, using snr_back + const edgeKey = (a, b) => `${String(a)}->${String(b)}`; + const edges = new Map(); + + function upsertEdgesFromPath(trace, pathNodes, pathSnrs) { + for (let i = 0; i < pathNodes.length - 1; i++) { + const hopFrom = pathNodes[i]; + const hopTo = pathNodes[i + 1]; + const snr = typeof (pathSnrs && pathSnrs[i]) === 'number' ? pathSnrs[i] : null; + + // Skip edges without SNR data + if (snr === null) continue; + + const key = edgeKey(hopFrom, hopTo); + const existing = edges.get(key); + if (!existing) { + edges.set(key, { + from: hopFrom, + to: hopTo, + snr: snr, + updated_at: trace.updated_at, + channel_id: trace.channel_id ?? null, + gateway_id: trace.gateway_id ?? null, + traceroute_from: trace.from, // original initiator + traceroute_to: trace.to, // original target + }); + } else if (new Date(trace.updated_at) > new Date(existing.updated_at)) { + existing.snr = snr; + existing.updated_at = trace.updated_at; + existing.channel_id = trace.channel_id ?? existing.channel_id; + existing.gateway_id = trace.gateway_id ?? existing.gateway_id; + existing.traceroute_from = trace.from; + existing.traceroute_to = trace.to; + } + } + } + + for (const tr of normalized) { + // Forward path + const forwardPath = []; + if (tr.to != null) forwardPath.push(Number(tr.to)); + if (Array.isArray(tr.route)) { + for (const hop of tr.route) { + if (hop != null) forwardPath.push(Number(hop)); + } + } + if (tr.from != null) forwardPath.push(Number(tr.from)); + const forwardSnrs = Array.isArray(tr.snr_towards) ? tr.snr_towards : []; + upsertEdgesFromPath(tr, forwardPath, forwardSnrs); + + // Reverse path + const reversePath = []; + if (tr.from != null) reversePath.push(Number(tr.from)); + if (Array.isArray(tr.route_back)) { + for (const hop of tr.route_back) { + if (hop != null) reversePath.push(Number(hop)); + } + } + if (tr.to != null) reversePath.push(Number(tr.to)); + const reverseSnrs = Array.isArray(tr.snr_back) ? tr.snr_back : []; + upsertEdgesFromPath(tr, reversePath, reverseSnrs); + } + + res.json({ + traceroute_edges: Array.from(edges.values()), + }); + + } catch (err) { + console.error(err); + res.status(500).json({ + message: "Something went wrong, try again later.", + }); + } +}); + +// Aggregated edges endpoint +// GET /api/v1/connections?node_id=...&time_from=...&time_to=... +app.get('/api/v1/connections', async (req, res) => { + try { + const nodeId = req.query.node_id ? parseInt(req.query.node_id) : undefined; + const timeFrom = req.query.time_from ? parseInt(req.query.time_from) : undefined; + const timeTo = req.query.time_to ? parseInt(req.query.time_to) : undefined; + + // Query edges from database + const edges = await prisma.edge.findMany({ + where: { + created_at: { + ...(timeFrom && { gte: new Date(timeFrom) }), + ...(timeTo && { lte: new Date(timeTo) }), + }, + // Only include edges where both nodes have positions + from_latitude: { not: null }, + from_longitude: { not: null }, + to_latitude: { not: null }, + to_longitude: { not: null }, + // If node_id is provided, filter edges where either from_node_id or to_node_id matches + ...(nodeId !== undefined && { + OR: [ + { from_node_id: nodeId }, + { to_node_id: nodeId }, + ], + }), + }, + orderBy: [ + { created_at: 'desc' }, + { packet_id: 'desc' }, + ], + }); + + // Collect all unique node IDs from edges + const nodeIds = new Set(); + for (const edge of edges) { + nodeIds.add(edge.from_node_id); + nodeIds.add(edge.to_node_id); + } + + // Fetch current positions for all nodes + const nodes = await prisma.node.findMany({ + where: { + node_id: { in: Array.from(nodeIds) }, + }, + select: { + node_id: true, + latitude: true, + longitude: true, + }, + }); + + // Create a map of current node positions + const nodePositions = new Map(); + for (const node of nodes) { + nodePositions.set(node.node_id, { + latitude: node.latitude, + longitude: node.longitude, + }); + } + + // Filter edges: only include edges where both nodes are still at the same location + const validEdges = edges.filter(edge => { + const fromCurrentPos = nodePositions.get(edge.from_node_id); + const toCurrentPos = nodePositions.get(edge.to_node_id); + + // Skip if either node doesn't exist or doesn't have a current position + if (!fromCurrentPos || !toCurrentPos || + fromCurrentPos.latitude === null || fromCurrentPos.longitude === null || + toCurrentPos.latitude === null || toCurrentPos.longitude === null) { + return false; + } + + // Check if stored positions match current positions + const fromMatches = fromCurrentPos.latitude === edge.from_latitude && + fromCurrentPos.longitude === edge.from_longitude; + const toMatches = toCurrentPos.latitude === edge.to_latitude && + toCurrentPos.longitude === edge.to_longitude; + + return fromMatches && toMatches; + }); + + // Normalize node pairs: always use min/max to treat A->B and B->A as same connection + const connectionsMap = new Map(); + + for (const edge of validEdges) { + const nodeA = edge.from_node_id < edge.to_node_id ? edge.from_node_id : edge.to_node_id; + const nodeB = edge.from_node_id < edge.to_node_id ? edge.to_node_id : edge.from_node_id; + const key = `${nodeA}-${nodeB}`; + + if (!connectionsMap.has(key)) { + connectionsMap.set(key, { + node_a: nodeA, + node_b: nodeB, + direction_ab: [], // A -> B edges + direction_ba: [], // B -> A edges + }); + } + + const connection = connectionsMap.get(key); + const isAB = edge.from_node_id === nodeA; + + // Add edge to appropriate direction + if (isAB) { + connection.direction_ab.push({ + snr: edge.snr, + snr_db: edge.snr / 4, // Convert to dB + created_at: edge.created_at, + packet_id: edge.packet_id, + source: edge.source, + }); + } else { + connection.direction_ba.push({ + snr: edge.snr, + snr_db: edge.snr / 4, + created_at: edge.created_at, + packet_id: edge.packet_id, + source: edge.source, + }); + } + } + + // Aggregate each connection + const connections = Array.from(connectionsMap.values()).map(conn => { + // Deduplicate edges by packet_id for each direction (keep first occurrence, which is most recent) + const dedupeByPacketId = (edges) => { + const seen = new Set(); + return edges.filter(edge => { + if (seen.has(edge.packet_id)) { + return false; + } + seen.add(edge.packet_id); + return true; + }); + }; + + const deduplicatedAB = dedupeByPacketId(conn.direction_ab); + const deduplicatedBA = dedupeByPacketId(conn.direction_ba); + + // Calculate average SNR for A->B (using deduplicated edges) + const avgSnrAB = deduplicatedAB.length > 0 + ? deduplicatedAB.reduce((sum, e) => sum + e.snr_db, 0) / deduplicatedAB.length + : null; + + // Calculate average SNR for B->A (using deduplicated edges) + const avgSnrBA = deduplicatedBA.length > 0 + ? deduplicatedBA.reduce((sum, e) => sum + e.snr_db, 0) / deduplicatedBA.length + : null; + + // Get last 5 edges for each direction (already sorted by created_at DESC, packet_id DESC, now deduplicated) + const last5AB = deduplicatedAB.slice(0, 5); + const last5BA = deduplicatedBA.slice(0, 5); + + // Determine worst average SNR + const worstAvgSnrDb = [avgSnrAB, avgSnrBA] + .filter(v => v !== null) + .reduce((min, val) => val < min ? val : min, Infinity); + + return { + node_a: conn.node_a, + node_b: conn.node_b, + direction_ab: { + avg_snr_db: avgSnrAB, + last_5_edges: last5AB, + total_count: deduplicatedAB.length, // Use deduplicated count + }, + direction_ba: { + avg_snr_db: avgSnrBA, + last_5_edges: last5BA, + total_count: deduplicatedBA.length, // Use deduplicated count + }, + worst_avg_snr_db: worstAvgSnrDb !== Infinity ? worstAvgSnrDb : null, + }; + }).filter(conn => conn.worst_avg_snr_db !== null); // Only return connections with at least one direction + + res.json({ + connections: connections, + }); + + } catch (err) { + console.error(err); + res.status(500).json({ + message: "Something went wrong, try again later.", + }); + } +}); + app.get('/api/v1/nodes/:nodeId/position-history', async (req, res) => { try { @@ -646,42 +984,6 @@ app.get('/api/v1/nodes/:nodeId/position-history', async (req, res) => { } }); -app.get('/api/v1/stats/hardware-models', async (req, res) => { - try { - - // get nodes from db - const results = await prisma.node.groupBy({ - by: ['hardware_model'], - orderBy: { - _count: { - hardware_model: 'desc', - }, - }, - _count: { - hardware_model: true, - }, - }); - - const hardwareModelStats = results.map((result) => { - return { - count: result._count.hardware_model, - hardware_model: result.hardware_model, - hardware_model_name: HardwareModel.valuesById[result.hardware_model] ?? "UNKNOWN", - }; - }); - - res.json({ - hardware_model_stats: hardwareModelStats, - }); - - } catch(err) { - console.error(err); - res.status(500).json({ - message: "Something went wrong, try again later.", - }); - } -}); - app.get('/api/v1/text-messages', async (req, res) => { try { @@ -808,8 +1110,29 @@ app.get('/api/v1/waypoints', async (req, res) => { } }); + // start express server const listener = app.listen(port, () => { const port = listener.address().port; console.log(`Server running at http://127.0.0.1:${port}`); }); + +// Graceful shutdown handlers +function gracefulShutdown(signal) { + console.log(`Received ${signal}. Starting graceful shutdown...`); + + // Stop accepting new connections + listener.close(async (err) => { + console.log('HTTP server closed'); + await prisma.$disconnect(); + console.log('Database connections closed'); + console.log('Graceful shutdown completed'); + process.exit(0); + }); +} + +// Handle SIGTERM (Docker, systemd, etc.) +process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); + +// Handle SIGINT (Ctrl+C) +process.on('SIGINT', () => gracefulShutdown('SIGINT')); diff --git a/src/mqtt.js b/src/mqtt.js index f960619..67cb9dd 100644 --- a/src/mqtt.js +++ b/src/mqtt.js @@ -1,3 +1,4 @@ +require('./utils/logger'); const crypto = require("crypto"); const path = require("path"); const mqtt = require("mqtt"); @@ -222,6 +223,7 @@ const collectNeighbourInfo = options["collect-neighbour-info"] ?? false; const collectMapReports = options["collect-map-reports"] ?? false; const decryptionKeys = options["decryption-keys"] ?? [ "1PG7OiApB1nwvP+rz05pAQ==", // add default "AQ==" decryption key + "PjG/mVAqnannyvqmuYAwd0LZa1AV+wkcUQlacmexEXY=", // Årsta mesh? länkad av [x/0!] divideByZero i meshen ]; const dropPacketsNotOkToMqtt = options["drop-packets-not-ok-to-mqtt"] ?? false; const dropPortnumsWithoutBitfield = options["drop-portnums-without-bitfield"] ?? null; @@ -249,7 +251,7 @@ const client = mqtt.connect(mqttBrokerUrl, { // load protobufs const root = new protobufjs.Root(); -root.resolvePath = (origin, target) => path.join(__dirname, "protos", target); +root.resolvePath = (origin, target) => path.join(__dirname, "protobufs", target); root.loadSync('meshtastic/mqtt.proto'); const Data = root.lookupType("Data"); const ServiceEnvelope = root.lookupType("ServiceEnvelope"); @@ -262,8 +264,9 @@ const User = root.lookupType("User"); const Waypoint = root.lookupType("Waypoint"); // run automatic purge if configured +let purgeInterval = null; if(purgeIntervalSeconds){ - setInterval(async () => { + purgeInterval = setInterval(async () => { await purgeUnheardNodes(); await purgeOldDeviceMetrics(); await purgeOldEnvironmentMetrics(); @@ -739,6 +742,13 @@ client.on("message", async (topic, message) => { } } + + // check if bitfield is available, then set ok-to-mqtt + // else leave undefined to let Prisma ignore it. + let isOkToMqtt + if(bitfield != null){ + isOkToMqtt = Boolean(bitfield & BITFIELD_OK_TO_MQTT_MASK); + } // create service envelope in db if(collectServiceEnvelopes){ @@ -750,6 +760,8 @@ client.on("message", async (topic, message) => { gateway_id: envelope.gatewayId ? convertHexIdToNumericId(envelope.gatewayId) : null, to: envelope.packet.to, from: envelope.packet.from, + portnum: portnum, + packet_id: envelope.packet.id, protobuf: message, }, }); @@ -814,6 +826,7 @@ client.on("message", async (topic, message) => { rx_snr: envelope.packet.rxSnr, rx_rssi: envelope.packet.rxRssi, hop_limit: envelope.packet.hopLimit, + ok_to_mqtt: isOkToMqtt, }, }); } catch (e) { @@ -935,6 +948,19 @@ client.on("message", async (topic, message) => { hardware_model: user.hwModel, is_licensed: user.isLicensed === true, role: user.role, + is_unmessagable: user.isUnmessagable, + ok_to_mqtt: isOkToMqtt, + max_hops: envelope.packet.hopStart, + channel_id: envelope.channelId, + + firmware_version: '<2.5.0', + ...(user.publicKey != '' && { + firmware_version: '>2.5.0', + public_key: user.publicKey?.toString("base64"), + }), + ...(user.isUnmessagable != null && { + firmware_version: '>2.6.8', + }), }, update: { long_name: user.longName, @@ -942,12 +968,57 @@ client.on("message", async (topic, message) => { hardware_model: user.hwModel, is_licensed: user.isLicensed === true, role: user.role, + is_unmessagable: user.isUnmessagable, + ok_to_mqtt: isOkToMqtt, + max_hops: envelope.packet.hopStart, + channel_id: envelope.channelId, + + firmware_version: '<2.5.0', + ...(user.publicKey != '' && { + firmware_version: '>2.5.0', + public_key: user.publicKey?.toString("base64"), + }), + ...(user.isUnmessagable != null && { + firmware_version: '>2.6.8', + }), }, }); } catch (e) { - console.error(e); + // Ignore MySQL error 1020 "Record has changed since last read" - this is a race condition + // that occurs when multiple packets arrive concurrently for the same node + const errorMessage = e.message || String(e); + if (!errorMessage.includes('Record has changed since last read')) { + console.error(e); + } } + // Keep track of the names a node has been using. + try { + await prisma.NameHistory.upsert({ + where: { + node_id_long_name_short_name: { + node_id: envelope.packet.from, + long_name: user.longName, + short_name: user.shortName, + } + }, + create: { + node_id: envelope.packet.from, + long_name: user.longName, + short_name: user.shortName, + }, + update: { + updated_at: new Date(), + } + }); + } catch (e) { + // Ignore MySQL error 1020 "Record has changed since last read" - this is a race condition + // that occurs when multiple packets arrive concurrently for the same node + const errorMessage = e.message || String(e); + if (!errorMessage.includes('Record has changed since last read')) { + console.error(e); + } + } } else if(portnum === 8) { @@ -1023,6 +1094,70 @@ client.on("message", async (topic, message) => { console.error(e); } + // Extract edges from neighbour info + try { + const toNodeId = envelope.packet.from; + const neighbors = neighbourInfo.neighbors || []; + const packetId = envelope.packet.id; + const channelId = envelope.channelId; + const gatewayId = envelope.gatewayId ? convertHexIdToNumericId(envelope.gatewayId) : null; + const edgesToCreate = []; + + for(const neighbour of neighbors) { + // Skip if no node ID + if(!neighbour.nodeId) { + continue; + } + + // Skip if SNR is invalid (0 or null/undefined) + // Note: SNR can be negative, so we check for 0 specifically + if(neighbour.snr === 0 || neighbour.snr == null) { + continue; + } + + const fromNodeId = neighbour.nodeId; + const snr = neighbour.snr; + + // Fetch node positions from Node table + const [fromNode, toNode] = await Promise.all([ + prisma.node.findUnique({ + where: { node_id: fromNodeId }, + select: { latitude: true, longitude: true }, + }), + prisma.node.findUnique({ + where: { node_id: toNodeId }, + select: { latitude: true, longitude: true }, + }), + ]); + + // Create edge record + edgesToCreate.push({ + from_node_id: fromNodeId, + to_node_id: toNodeId, + snr: snr, + from_latitude: fromNode?.latitude ?? null, + from_longitude: fromNode?.longitude ?? null, + to_latitude: toNode?.latitude ?? null, + to_longitude: toNode?.longitude ?? null, + packet_id: packetId, + channel_id: channelId, + gateway_id: gatewayId, + source: "NEIGHBORINFO_APP", + }); + } + + // Bulk insert edges + if(edgesToCreate.length > 0) { + await prisma.edge.createMany({ + data: edgesToCreate, + skipDuplicates: true, // Skip if exact duplicate exists + }); + } + } catch (e) { + // Log error but don't crash - edge extraction is non-critical + console.error("Error extracting edges from neighbour info:", e); + } + // don't store all neighbour infos, but we want to update the existing node above if(!collectNeighbourInfo){ return; @@ -1265,6 +1400,160 @@ client.on("message", async (topic, message) => { console.error(e); } + // Extract edges from traceroute (only for response packets) + if(!envelope.packet.decoded.wantResponse) { + try { + const route = routeDiscovery.route || []; + const snrTowards = routeDiscovery.snrTowards || []; + const originNodeId = envelope.packet.to; + const destinationNodeId = envelope.packet.from; + const packetId = envelope.packet.id; + const channelId = envelope.channelId; + const gatewayId = envelope.gatewayId ? convertHexIdToNumericId(envelope.gatewayId) : null; + + // Determine number of edges: route.length + 1 + const numEdges = route.length + 1; + const edgesToCreate = []; + + // Extract edges from the route path + for(let i = 0; i < numEdges; i++) { + // Get SNR for this edge + if(i >= snrTowards.length) { + // Array length mismatch - skip this edge + continue; + } + + const snr = snrTowards[i]; + + // Skip if SNR is -128 (no SNR recorded) + if(snr === -128) { + continue; + } + + // Determine from_node and to_node + let fromNodeId, toNodeId; + + if(route.length === 0) { + // Empty route: direct connection (to -> from) + fromNodeId = originNodeId; + toNodeId = destinationNodeId; + } else if(i === 0) { + // First edge: origin -> route[0] + fromNodeId = originNodeId; + toNodeId = route[0]; + } else if(i === route.length) { + // Last edge: route[route.length-1] -> destination + fromNodeId = route[route.length - 1]; + toNodeId = destinationNodeId; + } else { + // Middle edge: route[i-1] -> route[i] + fromNodeId = route[i - 1]; + toNodeId = route[i]; + } + + // Fetch node positions from Node table + const [fromNode, toNode] = await Promise.all([ + prisma.node.findUnique({ + where: { node_id: fromNodeId }, + select: { latitude: true, longitude: true }, + }), + prisma.node.findUnique({ + where: { node_id: toNodeId }, + select: { latitude: true, longitude: true }, + }), + ]); + + // Create edge record (skip if nodes don't exist, but still create edge with null positions) + edgesToCreate.push({ + from_node_id: fromNodeId, + to_node_id: toNodeId, + snr: snr, + from_latitude: fromNode?.latitude ?? null, + from_longitude: fromNode?.longitude ?? null, + to_latitude: toNode?.latitude ?? null, + to_longitude: toNode?.longitude ?? null, + packet_id: packetId, + channel_id: channelId, + gateway_id: gatewayId, + source: "TRACEROUTE_APP", + }); + } + + // Extract edges from route_back path + const routeBack = routeDiscovery.routeBack || []; + const snrBack = routeDiscovery.snrBack || []; + + if(routeBack.length > 0) { + // Number of edges in route_back equals route_back.length + for(let i = 0; i < routeBack.length; i++) { + // Get SNR for this edge + if(i >= snrBack.length) { + // Array length mismatch - skip this edge + continue; + } + + const snr = snrBack[i]; + + // Skip if SNR is -128 (no SNR recorded) + if(snr === -128) { + continue; + } + + // Determine from_node and to_node + let fromNodeId, toNodeId; + + if(i === 0) { + // First edge: from -> route_back[0] + fromNodeId = destinationNodeId; // 'from' in the packet + toNodeId = routeBack[0]; + } else { + // Subsequent edges: route_back[i-1] -> route_back[i] + fromNodeId = routeBack[i - 1]; + toNodeId = routeBack[i]; + } + + // Fetch node positions from Node table + const [fromNode, toNode] = await Promise.all([ + prisma.node.findUnique({ + where: { node_id: fromNodeId }, + select: { latitude: true, longitude: true }, + }), + prisma.node.findUnique({ + where: { node_id: toNodeId }, + select: { latitude: true, longitude: true }, + }), + ]); + + // Create edge record + edgesToCreate.push({ + from_node_id: fromNodeId, + to_node_id: toNodeId, + snr: snr, + from_latitude: fromNode?.latitude ?? null, + from_longitude: fromNode?.longitude ?? null, + to_latitude: toNode?.latitude ?? null, + to_longitude: toNode?.longitude ?? null, + packet_id: packetId, + channel_id: channelId, + gateway_id: gatewayId, + source: "TRACEROUTE_APP", + }); + } + } + + // Bulk insert edges + if(edgesToCreate.length > 0) { + await prisma.edge.createMany({ + data: edgesToCreate, + skipDuplicates: true, // Skip if exact duplicate exists + }); + } + } catch (e) { + // Log error but don't crash - edge extraction is non-critical + console.error("Error extracting edges from traceroute:", e); + } + } + } else if(portnum === 73) { @@ -1369,6 +1658,7 @@ client.on("message", async (topic, message) => { || portnum === 0 // ignore UNKNOWN_APP || portnum === 1 // ignore TEXT_MESSAGE_APP || portnum === 5 // ignore ROUTING_APP + || portnum === 6 // ignore ADMIN_APP || portnum === 34 // ignore PAXCOUNTER_APP || portnum === 65 // ignore STORE_FORWARD_APP || portnum === 66 // ignore RANGE_TEST_APP @@ -1385,6 +1675,32 @@ client.on("message", async (topic, message) => { } } catch(e) { - // ignore errors + console.log("error", e); } }); + +// Graceful shutdown handlers +function gracefulShutdown(signal) { + console.log(`Received ${signal}. Starting graceful shutdown...`); + + // Clear the purge interval if it exists + if(purgeInterval) { + clearInterval(purgeInterval); + console.log('Purge interval cleared'); + } + + // Close MQTT client + client.end(false, async () => { + console.log('MQTT client disconnected'); + await prisma.$disconnect(); + console.log('Database connections closed'); + console.log('Graceful shutdown completed'); + process.exit(0); + }); +} + +// Handle SIGTERM (Docker, systemd, etc.) +process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); + +// Handle SIGINT (Ctrl+C) +process.on('SIGINT', () => gracefulShutdown('SIGINT')); diff --git a/src/protobufs b/src/protobufs new file mode 160000 index 0000000..c2e45a3 --- /dev/null +++ b/src/protobufs @@ -0,0 +1 @@ +Subproject commit c2e45a3fc9cda6aedb72ad3b5b88fcccfa78073e diff --git a/src/protos/meshtastic/admin.options b/src/protos/meshtastic/admin.options deleted file mode 100644 index 1d582e2..0000000 --- a/src/protos/meshtastic/admin.options +++ /dev/null @@ -1,12 +0,0 @@ -*AdminMessage.payload_variant anonymous_oneof:true - -*AdminMessage.set_canned_message_module_messages max_size:201 -*AdminMessage.get_canned_message_module_messages_response max_size:201 -*AdminMessage.delete_file_request max_size:201 - -*AdminMessage.set_ringtone_message max_size:231 -*AdminMessage.get_ringtone_response max_size:231 - -*HamParameters.call_sign max_size:8 -*HamParameters.short_name max_size:6 -*NodeRemoteHardwarePinsResponse.node_remote_hardware_pins max_count:16 \ No newline at end of file diff --git a/src/protos/meshtastic/admin.proto b/src/protos/meshtastic/admin.proto deleted file mode 100644 index 01295f4..0000000 --- a/src/protos/meshtastic/admin.proto +++ /dev/null @@ -1,364 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/channel.proto"; -import "meshtastic/config.proto"; -import "meshtastic/connection_status.proto"; -import "meshtastic/deviceonly.proto"; -import "meshtastic/mesh.proto"; -import "meshtastic/module_config.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "AdminProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This message is handled by the Admin module and is responsible for all settings/channel read/write operations. - * This message is used to do settings operations to both remote AND local nodes. - * (Prior to 1.2 these operations were done via special ToRadio operations) - */ -message AdminMessage { - /* - * TODO: REPLACE - */ - enum ConfigType { - /* - * TODO: REPLACE - */ - DEVICE_CONFIG = 0; - - /* - * TODO: REPLACE - */ - POSITION_CONFIG = 1; - - /* - * TODO: REPLACE - */ - POWER_CONFIG = 2; - - /* - * TODO: REPLACE - */ - NETWORK_CONFIG = 3; - - /* - * TODO: REPLACE - */ - DISPLAY_CONFIG = 4; - - /* - * TODO: REPLACE - */ - LORA_CONFIG = 5; - - /* - * TODO: REPLACE - */ - BLUETOOTH_CONFIG = 6; - } - - /* - * TODO: REPLACE - */ - enum ModuleConfigType { - /* - * TODO: REPLACE - */ - MQTT_CONFIG = 0; - - /* - * TODO: REPLACE - */ - SERIAL_CONFIG = 1; - - /* - * TODO: REPLACE - */ - EXTNOTIF_CONFIG = 2; - - /* - * TODO: REPLACE - */ - STOREFORWARD_CONFIG = 3; - - /* - * TODO: REPLACE - */ - RANGETEST_CONFIG = 4; - - /* - * TODO: REPLACE - */ - TELEMETRY_CONFIG = 5; - - /* - * TODO: REPLACE - */ - CANNEDMSG_CONFIG = 6; - - /* - * TODO: REPLACE - */ - AUDIO_CONFIG = 7; - - /* - * TODO: REPLACE - */ - REMOTEHARDWARE_CONFIG = 8; - - /* - * TODO: REPLACE - */ - NEIGHBORINFO_CONFIG = 9; - - /* - * TODO: REPLACE - */ - AMBIENTLIGHTING_CONFIG = 10; - - /* - * TODO: REPLACE - */ - DETECTIONSENSOR_CONFIG = 11; - - /* - * TODO: REPLACE - */ - PAXCOUNTER_CONFIG = 12; - } - - /* - * TODO: REPLACE - */ - oneof payload_variant { - /* - * Send the specified channel in the response to this message - * NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) - */ - uint32 get_channel_request = 1; - - /* - * TODO: REPLACE - */ - Channel get_channel_response = 2; - - /* - * Send the current owner data in the response to this message. - */ - bool get_owner_request = 3; - - /* - * TODO: REPLACE - */ - User get_owner_response = 4; - - /* - * Ask for the following config data to be sent - */ - ConfigType get_config_request = 5; - - /* - * Send the current Config in the response to this message. - */ - Config get_config_response = 6; - - /* - * Ask for the following config data to be sent - */ - ModuleConfigType get_module_config_request = 7; - - /* - * Send the current Config in the response to this message. - */ - ModuleConfig get_module_config_response = 8; - - /* - * Get the Canned Message Module messages in the response to this message. - */ - bool get_canned_message_module_messages_request = 10; - - /* - * Get the Canned Message Module messages in the response to this message. - */ - string get_canned_message_module_messages_response = 11; - - /* - * Request the node to send device metadata (firmware, protobuf version, etc) - */ - bool get_device_metadata_request = 12; - - /* - * Device metadata response - */ - DeviceMetadata get_device_metadata_response = 13; - - /* - * Get the Ringtone in the response to this message. - */ - bool get_ringtone_request = 14; - - /* - * Get the Ringtone in the response to this message. - */ - string get_ringtone_response = 15; - - /* - * Request the node to send it's connection status - */ - bool get_device_connection_status_request = 16; - - /* - * Device connection status response - */ - DeviceConnectionStatus get_device_connection_status_response = 17; - - /* - * Setup a node for licensed amateur (ham) radio operation - */ - HamParameters set_ham_mode = 18; - - /* - * Get the mesh's nodes with their available gpio pins for RemoteHardware module use - */ - bool get_node_remote_hardware_pins_request = 19; - - /* - * Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use - */ - NodeRemoteHardwarePinsResponse get_node_remote_hardware_pins_response = 20; - - /* - * Enter (UF2) DFU mode - * Only implemented on NRF52 currently - */ - bool enter_dfu_mode_request = 21; - - /* - * Delete the file by the specified path from the device - */ - string delete_file_request = 22; - - /* - * Set the owner for this node - */ - User set_owner = 32; - - /* - * Set channels (using the new API). - * A special channel is the "primary channel". - * The other records are secondary channels. - * Note: only one channel can be marked as primary. - * If the client sets a particular channel to be primary, the previous channel will be set to SECONDARY automatically. - */ - Channel set_channel = 33; - - /* - * Set the current Config - */ - Config set_config = 34; - - /* - * Set the current Config - */ - ModuleConfig set_module_config = 35; - - /* - * Set the Canned Message Module messages text. - */ - string set_canned_message_module_messages = 36; - - /* - * Set the ringtone for ExternalNotification. - */ - string set_ringtone_message = 37; - - /* - * Remove the node by the specified node-num from the NodeDB on the device - */ - uint32 remove_by_nodenum = 38; - - /* - * Begins an edit transaction for config, module config, owner, and channel settings changes - * This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) - */ - bool begin_edit_settings = 64; - - /* - * Commits an open transaction for any edits made to config, module config, owner, and channel settings - */ - bool commit_edit_settings = 65; - - /* - * Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) - * Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. - */ - int32 reboot_ota_seconds = 95; - - /* - * This message is only supported for the simulator Portduino build. - * If received the simulator will exit successfully. - */ - bool exit_simulator = 96; - - /* - * Tell the node to reboot in this many seconds (or <0 to cancel reboot) - */ - int32 reboot_seconds = 97; - - /* - * Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) - */ - int32 shutdown_seconds = 98; - - /* - * Tell the node to factory reset, all device settings will be returned to factory defaults. - */ - int32 factory_reset = 99; - - /* - * Tell the node to reset the nodedb. - */ - int32 nodedb_reset = 100; - } -} - -/* - * Parameters for setting up Meshtastic for ameteur radio usage - */ -message HamParameters { - /* - * Amateur radio call sign, eg. KD2ABC - */ - string call_sign = 1; - - /* - * Transmit power in dBm at the LoRA transceiver, not including any amplification - */ - int32 tx_power = 2; - - /* - * The selected frequency of LoRA operation - * Please respect your local laws, regulations, and band plans. - * Ensure your radio is capable of operating of the selected frequency before setting this. - */ - float frequency = 3; - - /* - * Optional short name of user - */ - string short_name = 4; -} - -/* - * Response envelope for node_remote_hardware_pins - */ -message NodeRemoteHardwarePinsResponse { - /* - * Nodes and their respective remote hardware GPIO pins - */ - repeated NodeRemoteHardwarePin node_remote_hardware_pins = 1; -} diff --git a/src/protos/meshtastic/apponly.options b/src/protos/meshtastic/apponly.options deleted file mode 100644 index 28244de..0000000 --- a/src/protos/meshtastic/apponly.options +++ /dev/null @@ -1 +0,0 @@ -*ChannelSet.settings max_count:8 diff --git a/src/protos/meshtastic/apponly.proto b/src/protos/meshtastic/apponly.proto deleted file mode 100644 index 100833f..0000000 --- a/src/protos/meshtastic/apponly.proto +++ /dev/null @@ -1,31 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/channel.proto"; -import "meshtastic/config.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "AppOnlyProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This is the most compact possible representation for a set of channels. - * It includes only one PRIMARY channel (which must be first) and - * any SECONDARY channels. - * No DISABLED channels are included. - * This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL - */ -message ChannelSet { - /* - * Channel list with settings - */ - repeated ChannelSettings settings = 1; - - /* - * LoRa config - */ - Config.LoRaConfig lora_config = 2; -} diff --git a/src/protos/meshtastic/atak.options b/src/protos/meshtastic/atak.options deleted file mode 100644 index c341400..0000000 --- a/src/protos/meshtastic/atak.options +++ /dev/null @@ -1,6 +0,0 @@ -*Contact.callsign max_size:120 -*Contact.device_callsign max_size:120 -*Status.battery int_size:8 -*PLI.course int_size:16 -*GeoChat.message max_size:200 -*GeoChat.to max_size:120 \ No newline at end of file diff --git a/src/protos/meshtastic/atak.proto b/src/protos/meshtastic/atak.proto deleted file mode 100644 index c44479f..0000000 --- a/src/protos/meshtastic/atak.proto +++ /dev/null @@ -1,251 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ATAKProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; -/* - * Packets for the official ATAK Plugin - */ -message TAKPacket -{ - /* - * Are the payloads strings compressed for LoRA transport? - */ - bool is_compressed = 1; - /* - * The contact / callsign for ATAK user - */ - Contact contact = 2; - /* - * The group for ATAK user - */ - Group group = 3; - /* - * The status of the ATAK EUD - */ - Status status = 4; - /* - * The payload of the packet - */ - oneof payload_variant { - /* - * TAK position report - */ - PLI pli = 5; - /* - * ATAK GeoChat message - */ - GeoChat chat = 6; - } -} - -/* - * ATAK GeoChat message - */ -message GeoChat { - /* - * The text message - */ - string message = 1; - - /* - * Uid recipient of the message - */ - optional string to = 2; -} - -/* - * ATAK Group - * <__group role='Team Member' name='Cyan'/> - */ -message Group { - /* - * Role of the group member - */ - MemberRole role = 1; - /* - * Team (color) - * Default Cyan - */ - Team team = 2; -} - -enum Team { - /* - * Unspecifed - */ - Unspecifed_Color = 0; - /* - * White - */ - White = 1; - /* - * Yellow - */ - Yellow = 2; - /* - * Orange - */ - Orange = 3; - /* - * Magenta - */ - Magenta = 4; - /* - * Red - */ - Red = 5; - /* - * Maroon - */ - Maroon = 6; - /* - * Purple - */ - Purple = 7; - /* - * Dark Blue - */ - Dark_Blue = 8; - /* - * Blue - */ - Blue = 9; - /* - * Cyan - */ - Cyan = 10; - /* - * Teal - */ - Teal = 11; - /* - * Green - */ - Green = 12; - /* - * Dark Green - */ - Dark_Green = 13; - /* - * Brown - */ - Brown = 14; -} - -/* - * Role of the group member - */ -enum MemberRole { - /* - * Unspecifed - */ - Unspecifed = 0; - /* - * Team Member - */ - TeamMember = 1; - /* - * Team Lead - */ - TeamLead = 2; - /* - * Headquarters - */ - HQ = 3; - /* - * Airsoft enthusiast - */ - Sniper = 4; - /* - * Medic - */ - Medic = 5; - /* - * ForwardObserver - */ - ForwardObserver = 6; - /* - * Radio Telephone Operator - */ - RTO = 7; - /* - * Doggo - */ - K9 = 8; -} - -/* - * ATAK EUD Status - * - */ -message Status { - /* - * Battery level - */ - uint32 battery = 1; -} -/* - * ATAK Contact - * - */ -message Contact { - /* - * Callsign - */ - string callsign = 1; - - /* - * Device callsign - */ - string device_callsign = 2; - /* - * IP address of endpoint in integer form (0.0.0.0 default) - */ - // fixed32 enpoint_address = 3; - /* - * Port of endpoint (4242 default) - */ - // uint32 endpoint_port = 4; - /* - * Phone represented as integer - * Terrible practice, but we really need the wire savings - */ - // uint32 phone = 4; -} - -/* - * Position Location Information from ATAK - */ -message PLI { - /* - * The new preferred location encoding, multiply by 1e-7 to get degrees - * in floating point - */ - sfixed32 latitude_i = 1; - - /* - * The new preferred location encoding, multiply by 1e-7 to get degrees - * in floating point - */ - sfixed32 longitude_i = 2; - - /* - * Altitude (ATAK prefers HAE) - */ - int32 altitude = 3; - - /* - * Speed - */ - uint32 speed = 4; - - /* - * Course in degrees - */ - uint32 course = 5; -} diff --git a/src/protos/meshtastic/cannedmessages.options b/src/protos/meshtastic/cannedmessages.options deleted file mode 100644 index c1d537b..0000000 --- a/src/protos/meshtastic/cannedmessages.options +++ /dev/null @@ -1 +0,0 @@ -*CannedMessageModuleConfig.messages max_size:201 diff --git a/src/protos/meshtastic/cannedmessages.proto b/src/protos/meshtastic/cannedmessages.proto deleted file mode 100644 index baa5134..0000000 --- a/src/protos/meshtastic/cannedmessages.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "CannedMessageConfigProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * Canned message module configuration. - */ -message CannedMessageModuleConfig { - /* - * Predefined messages for canned message module separated by '|' characters. - */ - string messages = 1; -} diff --git a/src/protos/meshtastic/channel.options b/src/protos/meshtastic/channel.options deleted file mode 100644 index d0bdcbc..0000000 --- a/src/protos/meshtastic/channel.options +++ /dev/null @@ -1,5 +0,0 @@ -*Channel.index int_size:8 - -# 256 bit or 128 bit psk key -*ChannelSettings.psk max_size:32 -*ChannelSettings.name max_size:12 diff --git a/src/protos/meshtastic/channel.proto b/src/protos/meshtastic/channel.proto deleted file mode 100644 index 2b10aaf..0000000 --- a/src/protos/meshtastic/channel.proto +++ /dev/null @@ -1,150 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ChannelProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This information can be encoded as a QRcode/url so that other users can configure - * their radio to join the same channel. - * A note about how channel names are shown to users: channelname-X - * poundsymbol is a prefix used to indicate this is a channel name (idea from @professr). - * Where X is a letter from A-Z (base 26) representing a hash of the PSK for this - * channel - so that if the user changes anything about the channel (which does - * force a new PSK) this letter will also change. Thus preventing user confusion if - * two friends try to type in a channel name of "BobsChan" and then can't talk - * because their PSKs will be different. - * The PSK is hashed into this letter by "0x41 + [xor all bytes of the psk ] modulo 26" - * This also allows the option of someday if people have the PSK off (zero), the - * users COULD type in a channel name and be able to talk. - * FIXME: Add description of multi-channel support and how primary vs secondary channels are used. - * FIXME: explain how apps use channels for security. - * explain how remote settings and remote gpio are managed as an example - */ -message ChannelSettings { - /* - * Deprecated in favor of LoraConfig.channel_num - */ - uint32 channel_num = 1 [deprecated = true]; - - /* - * A simple pre-shared key for now for crypto. - * Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256). - * A special shorthand is used for 1 byte long psks. - * These psks should be treated as only minimally secure, - * because they are listed in this source code. - * Those bytes are mapped using the following scheme: - * `0` = No crypto - * `1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01} - * `2` through 10 = The default channel key, except with 1 through 9 added to the last byte. - * Shown to user as simple1 through 10 - */ - bytes psk = 2; - - /* - * A SHORT name that will be packed into the URL. - * Less than 12 bytes. - * Something for end users to call the channel - * If this is the empty string it is assumed that this channel - * is the special (minimally secure) "Default"channel. - * In user interfaces it should be rendered as a local language translation of "X". - * For channel_num hashing empty string will be treated as "X". - * Where "X" is selected based on the English words listed above for ModemPreset - */ - string name = 3; - - /* - * Used to construct a globally unique channel ID. - * The full globally unique ID will be: "name.id" where ID is shown as base36. - * Assuming that the number of meshtastic users is below 20K (true for a long time) - * the chance of this 64 bit random number colliding with anyone else is super low. - * And the penalty for collision is low as well, it just means that anyone trying to decrypt channel messages might need to - * try multiple candidate channels. - * Any time a non wire compatible change is made to a channel, this field should be regenerated. - * There are a small number of 'special' globally known (and fairly) insecure standard channels. - * Those channels do not have a numeric id included in the settings, but instead it is pulled from - * a table of well known IDs. - * (see Well Known Channels FIXME) - */ - fixed32 id = 4; - - /* - * If true, messages on the mesh will be sent to the *public* internet by any gateway ndoe - */ - bool uplink_enabled = 5; - - /* - * If true, messages seen on the internet will be forwarded to the local mesh. - */ - bool downlink_enabled = 6; - - /* - * Per-channel module settings. - */ - ModuleSettings module_settings = 7; -} - -/* - * This message is specifically for modules to store per-channel configuration data. - */ -message ModuleSettings { -/* - * Bits of precision for the location sent in position packets. - */ - uint32 position_precision = 1; -} - -/* - * A pair of a channel number, mode and the (sharable) settings for that channel - */ -message Channel { - /* - * How this channel is being used (or not). - * Note: this field is an enum to give us options for the future. - * In particular, someday we might make a 'SCANNING' option. - * SCANNING channels could have different frequencies and the radio would - * occasionally check that freq to see if anything is being transmitted. - * For devices that have multiple physical radios attached, we could keep multiple PRIMARY/SCANNING channels active at once to allow - * cross band routing as needed. - * If a device has only a single radio (the common case) only one channel can be PRIMARY at a time - * (but any number of SECONDARY channels can't be sent received on that common frequency) - */ - enum Role { - /* - * This channel is not in use right now - */ - DISABLED = 0; - - /* - * This channel is used to set the frequency for the radio - all other enabled channels must be SECONDARY - */ - PRIMARY = 1; - - /* - * Secondary channels are only used for encryption/decryption/authentication purposes. - * Their radio settings (freq etc) are ignored, only psk is used. - */ - SECONDARY = 2; - } - - /* - * The index of this channel in the channel table (from 0 to MAX_NUM_CHANNELS-1) - * (Someday - not currently implemented) An index of -1 could be used to mean "set by name", - * in which case the target node will find and set the channel by settings.name. - */ - int32 index = 1; - - /* - * The new settings, or NULL to disable that channel - */ - ChannelSettings settings = 2; - - /* - * TODO: REPLACE - */ - Role role = 3; -} diff --git a/src/protos/meshtastic/clientonly.options b/src/protos/meshtastic/clientonly.options deleted file mode 100644 index bc98b39..0000000 --- a/src/protos/meshtastic/clientonly.options +++ /dev/null @@ -1,2 +0,0 @@ -*DeviceProfile.long_name max_size:40 -*DeviceProfile.short_name max_size:5 \ No newline at end of file diff --git a/src/protos/meshtastic/clientonly.proto b/src/protos/meshtastic/clientonly.proto deleted file mode 100644 index 1d58b11..0000000 --- a/src/protos/meshtastic/clientonly.proto +++ /dev/null @@ -1,50 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/localonly.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ClientOnlyProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This abstraction is used to contain any configuration for provisioning a node on any client. - * It is useful for importing and exporting configurations. - */ -message DeviceProfile { - /* - * Long name for the node - */ - optional string long_name = 1; - - /* - * Short name of the node - */ - optional string short_name = 2; - - /* - * The url of the channels from our node - */ - optional string channel_url = 3; - - /* - * The Config of the node - */ - optional LocalConfig config = 4; - - /* - * The ModuleConfig of the node - */ - optional LocalModuleConfig module_config = 5; -} - -/* - * A heartbeat message is sent by a node to indicate that it is still alive. - * This is currently only needed to keep serial connections alive. - */ -message Heartbeat { - -} diff --git a/src/protos/meshtastic/config.options b/src/protos/meshtastic/config.options deleted file mode 100644 index 4490f08..0000000 --- a/src/protos/meshtastic/config.options +++ /dev/null @@ -1,14 +0,0 @@ -*NetworkConfig.wifi_ssid max_size:33 -*NetworkConfig.wifi_psk max_size:65 -*NetworkConfig.ntp_server max_size:33 -*NetworkConfig.rsyslog_server max_size:33 - -# Max of three ignored nodes for our testing -*LoRaConfig.ignore_incoming max_count:3 - -*LoRaConfig.tx_power int_size:8 -*LoRaConfig.bandwidth int_size:16 -*LoRaConfig.coding_rate int_size:8 -*LoRaConfig.channel_num int_size:16 - -*PowerConfig.device_battery_ina_address int_size:8 diff --git a/src/protos/meshtastic/config.proto b/src/protos/meshtastic/config.proto deleted file mode 100644 index 9bca4d2..0000000 --- a/src/protos/meshtastic/config.proto +++ /dev/null @@ -1,986 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ConfigProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -message Config { - /* - * Configuration - */ - message DeviceConfig { - /* - * Defines the device's role on the Mesh network - */ - enum Role { - /* - * Description: App connected or stand alone messaging device. - * Technical Details: Default Role - */ - CLIENT = 0; - /* - * Description: Device that does not forward packets from other devices. - */ - CLIENT_MUTE = 1; - - /* - * Description: Infrastructure node for extending network coverage by relaying messages. Visible in Nodes list. - * Technical Details: Mesh packets will prefer to be routed over this node. This node will not be used by client apps. - * The wifi radio and the oled screen will be put to sleep. - * This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. - */ - ROUTER = 2; - - /* - * Description: Combination of both ROUTER and CLIENT. Not for mobile devices. - */ - ROUTER_CLIENT = 3; - - /* - * Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list. - * Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry - * or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. - */ - REPEATER = 4; - - /* - * Description: Broadcasts GPS position packets as priority. - * Technical Details: Position Mesh packets will be prioritized higher and sent more frequently by default. - * When used in conjunction with power.is_power_saving = true, nodes will wake up, - * send position, and then sleep for position.position_broadcast_secs seconds. - */ - TRACKER = 5; - - /* - * Description: Broadcasts telemetry packets as priority. - * Technical Details: Telemetry Mesh packets will be prioritized higher and sent more frequently by default. - * When used in conjunction with power.is_power_saving = true, nodes will wake up, - * send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. - */ - SENSOR = 6; - - /* - * Description: Optimized for ATAK system communication and reduces routine broadcasts. - * Technical Details: Used for nodes dedicated for connection to an ATAK EUD. - * Turns off many of the routine broadcasts to favor CoT packet stream - * from the Meshtastic ATAK plugin -> IMeshService -> Node - */ - TAK = 7; - - /* - * Description: Device that only broadcasts as needed for stealth or power savings. - * Technical Details: Used for nodes that "only speak when spoken to" - * Turns all of the routine broadcasts but allows for ad-hoc communication - * Still rebroadcasts, but with local only rebroadcast mode (known meshes only) - * Can be used for clandestine operation or to dramatically reduce airtime / power consumption - */ - CLIENT_HIDDEN = 8; - - /* - * Description: Broadcasts location as message to default channel regularly for to assist with device recovery. - * Technical Details: Used to automatically send a text message to the mesh - * with the current position of the device on a frequent interval: - * "I'm lost! Position: lat / long" - */ - LOST_AND_FOUND = 9; - - /* - * Description: Enables automatic TAK PLI broadcasts and reduces routine broadcasts. - * Technical Details: Turns off many of the routine broadcasts to favor ATAK CoT packet stream - * and automatic TAK PLI (position location information) broadcasts. - * Uses position module configuration to determine TAK PLI broadcast interval. - */ - TAK_TRACKER = 10; - - /* - * Description: Will always rebroadcast packets, but will do so after all other modes. - * Technical Details: Used for router nodes that are intended to provide additional coverage - * in areas not already covered by other routers, or to bridge around problematic terrain, - * but should not be given priority over other routers in order to avoid unnecessaraily - * consuming hops. - */ - ROUTER_LATE = 11; - } - - /* - * Defines the device's behavior for how messages are rebroadcast - */ - enum RebroadcastMode { - /* - * Default behavior. - * Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params. - */ - ALL = 0; - - /* - * Same as behavior as ALL but skips packet decoding and simply rebroadcasts them. - * Only available in Repeater role. Setting this on any other roles will result in ALL behavior. - */ - ALL_SKIP_DECODING = 1; - - /* - * Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. - * Only rebroadcasts message on the nodes local primary / secondary channels. - */ - LOCAL_ONLY = 2; - - /* - * Ignores observed messages from foreign meshes like LOCAL_ONLY, - * but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB) - */ - KNOWN_ONLY = 3; - } - - /* - * Sets the role of node - */ - Role role = 1; - - /* - * Disabling this will disable the SerialConsole by not initilizing the StreamAPI - */ - bool serial_enabled = 2; - - /* - * By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - * Set this to true to leave the debug log outputting even when API is active. - */ - bool debug_log_enabled = 3; - - /* - * For boards without a hard wired button, this is the pin number that will be used - * Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. - */ - uint32 button_gpio = 4; - - /* - * For boards without a PWM buzzer, this is the pin number that will be used - * Defaults to PIN_BUZZER if defined. - */ - uint32 buzzer_gpio = 5; - - /* - * Sets the role of node - */ - RebroadcastMode rebroadcast_mode = 6; - - /* - * Send our nodeinfo this often - * Defaults to 900 Seconds (15 minutes) - */ - uint32 node_info_broadcast_secs = 7; - - /* - * Treat double tap interrupt on supported accelerometers as a button press if set to true - */ - bool double_tap_as_button_press = 8; - - /* - * If true, device is considered to be "managed" by a mesh administrator - * Clients should then limit available configuration and administrative options inside the user interface - */ - bool is_managed = 9; - - /* - * Disables the triple-press of user button to enable or disable GPS - */ - bool disable_triple_click = 10; - } - - /* - * Position Config - */ - message PositionConfig { - /* - * Bit field of boolean configuration options, indicating which optional - * fields to include when assembling POSITION messages. - * Longitude, latitude, altitude, speed, heading, and DOP - * are always included (also time if GPS-synced) - * NOTE: the more fields are included, the larger the message will be - - * leading to longer airtime and a higher risk of packet loss - */ - enum PositionFlags { - /* - * Required for compilation - */ - UNSET = 0x0000; - - /* - * Include an altitude value (if available) - */ - ALTITUDE = 0x0001; - - /* - * Altitude value is MSL - */ - ALTITUDE_MSL = 0x0002; - - /* - * Include geoidal separation - */ - GEOIDAL_SEPARATION = 0x0004; - - /* - * Include the DOP value ; PDOP used by default, see below - */ - DOP = 0x0008; - - /* - * If POS_DOP set, send separate HDOP / VDOP values instead of PDOP - */ - HVDOP = 0x0010; - - /* - * Include number of "satellites in view" - */ - SATINVIEW = 0x0020; - - /* - * Include a sequence number incremented per packet - */ - SEQ_NO = 0x0040; - - /* - * Include positional timestamp (from GPS solution) - */ - TIMESTAMP = 0x0080; - - /* - * Include positional heading - * Intended for use with vehicle not walking speeds - * walking speeds are likely to be error prone like the compass - */ - HEADING = 0x0100; - - /* - * Include positional speed - * Intended for use with vehicle not walking speeds - * walking speeds are likely to be error prone like the compass - */ - SPEED = 0x0200; - } - - enum GpsMode { - /* - * GPS is present but disabled - */ - DISABLED = 0; - - /* - * GPS is present and enabled - */ - ENABLED = 1; - - /* - * GPS is not present on the device - */ - NOT_PRESENT = 2; - } - - /* - * We should send our position this often (but only if it has changed significantly) - * Defaults to 15 minutes - */ - uint32 position_broadcast_secs = 1; - - /* - * Adaptive position braoadcast, which is now the default. - */ - bool position_broadcast_smart_enabled = 2; - - /* - * If set, this node is at a fixed position. - * We will generate GPS position updates at the regular interval, but use whatever the last lat/lon/alt we have for the node. - * The lat/lon/alt can be set by an internal GPS or with the help of the app. - */ - bool fixed_position = 3; - - /* - * Is GPS enabled for this node? - */ - bool gps_enabled = 4[deprecated = true]; - - /* - * How often should we try to get GPS position (in seconds) - * or zero for the default of once every 30 seconds - * or a very large value (maxint) to update only once at boot. - */ - uint32 gps_update_interval = 5; - - /* - * Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time - */ - uint32 gps_attempt_time = 6 [deprecated = true]; - - /* - * Bit field of boolean configuration options for POSITION messages - * (bitwise OR of PositionFlags) - */ - uint32 position_flags = 7; - - /* - * (Re)define GPS_RX_PIN for your board. - */ - uint32 rx_gpio = 8; - - /* - * (Re)define GPS_TX_PIN for your board. - */ - uint32 tx_gpio = 9; - - /* - * The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled - */ - uint32 broadcast_smart_minimum_distance = 10; - - /* - * The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled - */ - uint32 broadcast_smart_minimum_interval_secs = 11; - - /* - * (Re)define PIN_GPS_EN for your board. - */ - uint32 gps_en_gpio = 12; - - /* - * Set where GPS is enabled, disabled, or not present - */ - GpsMode gps_mode = 13; - } - - /* - * Power Config\ - * See [Power Config](/docs/settings/config/power) for additional power config details. - */ - message PowerConfig { - /* - * If set, we are powered from a low-current source (i.e. solar), so even if it looks like we have power flowing in - * we should try to minimize power consumption as much as possible. - * YOU DO NOT NEED TO SET THIS IF YOU'VE set is_router (it is implied in that case). - * Advanced Option - */ - bool is_power_saving = 1; - - /* - * If non-zero, the device will fully power off this many seconds after external power is removed. - */ - uint32 on_battery_shutdown_after_secs = 2; - - /* - * Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k) - * Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation. - * Should be set to floating point value between 2 and 4 - * Fixes issues on Heltec v2 - */ - float adc_multiplier_override = 3; - - /* - * Wait Bluetooth Seconds - * The number of seconds for to wait before turning off BLE in No Bluetooth states - * 0 for default of 1 minute - */ - uint32 wait_bluetooth_secs = 4; - - /* - * Super Deep Sleep Seconds - * While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep - * for this value (default 1 year) or a button press - * 0 for default of one year - */ - uint32 sds_secs = 6; - - /* - * Light Sleep Seconds - * In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on - * ESP32 Only - * 0 for default of 300 - */ - uint32 ls_secs = 7; - - /* - * Minimum Wake Seconds - * While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value - * 0 for default of 10 seconds - */ - uint32 min_wake_secs = 8; - - /* - * I2C address of INA_2XX to use for reading device battery voltage - */ - uint32 device_battery_ina_address = 9; - } - - /* - * Network Config - */ - message NetworkConfig { - enum AddressMode { - /* - * obtain ip address via DHCP - */ - DHCP = 0; - - /* - * use static ip address - */ - STATIC = 1; - } - - message IpV4Config { - /* - * Static IP address - */ - fixed32 ip = 1; - - /* - * Static gateway address - */ - fixed32 gateway = 2; - - /* - * Static subnet mask - */ - fixed32 subnet = 3; - - /* - * Static DNS server address - */ - fixed32 dns = 4; - } - - /* - * Enable WiFi (disables Bluetooth) - */ - bool wifi_enabled = 1; - - /* - * If set, this node will try to join the specified wifi network and - * acquire an address via DHCP - */ - string wifi_ssid = 3; - - /* - * If set, will be use to authenticate to the named wifi - */ - string wifi_psk = 4; - - /* - * NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org` - */ - string ntp_server = 5; - - /* - * Enable Ethernet - */ - bool eth_enabled = 6; - - /* - * acquire an address via DHCP or assign static - */ - AddressMode address_mode = 7; - - /* - * struct to keep static address - */ - IpV4Config ipv4_config = 8; - - /* - * rsyslog Server and Port - */ - string rsyslog_server = 9; - } - - /* - * Display Config - */ - message DisplayConfig { - /* - * How the GPS coordinates are displayed on the OLED screen. - */ - enum GpsCoordinateFormat { - /* - * GPS coordinates are displayed in the normal decimal degrees format: - * DD.DDDDDD DDD.DDDDDD - */ - DEC = 0; - - /* - * GPS coordinates are displayed in the degrees minutes seconds format: - * DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant - */ - DMS = 1; - - /* - * Universal Transverse Mercator format: - * ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing - */ - UTM = 2; - - /* - * Military Grid Reference System format: - * ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, - * E is easting, N is northing - */ - MGRS = 3; - - /* - * Open Location Code (aka Plus Codes). - */ - OLC = 4; - - /* - * Ordnance Survey Grid Reference (the National Grid System of the UK). - * Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, - * E is the easting, N is the northing - */ - OSGR = 5; - } - - /* - * Unit display preference - */ - enum DisplayUnits { - /* - * Metric (Default) - */ - METRIC = 0; - - /* - * Imperial - */ - IMPERIAL = 1; - } - - /* - * Override OLED outo detect with this if it fails. - */ - enum OledType { - /* - * Default / Auto - */ - OLED_AUTO = 0; - - /* - * Default / Auto - */ - OLED_SSD1306 = 1; - - /* - * Default / Auto - */ - OLED_SH1106 = 2; - - /* - * Can not be auto detected but set by proto. Used for 128x128 screens - */ - OLED_SH1107 = 3; - } - - /* - * Number of seconds the screen stays on after pressing the user button or receiving a message - * 0 for default of one minute MAXUINT for always on - */ - uint32 screen_on_secs = 1; - - /* - * How the GPS coordinates are formatted on the OLED screen. - */ - GpsCoordinateFormat gps_format = 2; - - /* - * Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. - * Potentially useful for devices without user buttons. - */ - uint32 auto_screen_carousel_secs = 3; - - /* - * If this is set, the displayed compass will always point north. if unset, the old behaviour - * (top of display is heading direction) is used. - */ - bool compass_north_top = 4; - - /* - * Flip screen vertically, for cases that mount the screen upside down - */ - bool flip_screen = 5; - - /* - * Perferred display units - */ - DisplayUnits units = 6; - - /* - * Override auto-detect in screen - */ - OledType oled = 7; - - enum DisplayMode { - /* - * Default. The old style for the 128x64 OLED screen - */ - DEFAULT = 0; - - /* - * Rearrange display elements to cater for bicolor OLED displays - */ - TWOCOLOR = 1; - - /* - * Same as TwoColor, but with inverted top bar. Not so good for Epaper displays - */ - INVERTED = 2; - - /* - * TFT Full Color Displays (not implemented yet) - */ - COLOR = 3; - } - /* - * Display Mode - */ - DisplayMode displaymode = 8; - - /* - * Print first line in pseudo-bold? FALSE is original style, TRUE is bold - */ - bool heading_bold = 9; - - /* - * Should we wake the screen up on accelerometer detected motion or tap - */ - bool wake_on_tap_or_motion = 10; - } - - /* - * Lora Config - */ - message LoRaConfig { - enum RegionCode { - /* - * Region is not set - */ - UNSET = 0; - - /* - * United States - */ - US = 1; - - /* - * European Union 433mhz - */ - EU_433 = 2; - - /* - * European Union 868mhz - */ - EU_868 = 3; - - /* - * China - */ - CN = 4; - - /* - * Japan - */ - JP = 5; - - /* - * Australia / New Zealand - */ - ANZ = 6; - - /* - * Korea - */ - KR = 7; - - /* - * Taiwan - */ - TW = 8; - - /* - * Russia - */ - RU = 9; - - /* - * India - */ - IN = 10; - - /* - * New Zealand 865mhz - */ - NZ_865 = 11; - - /* - * Thailand - */ - TH = 12; - - /* - * WLAN Band - */ - LORA_24 = 13; - - /* - * Ukraine 433mhz - */ - UA_433 = 14; - - /* - * Ukraine 868mhz - */ - UA_868 = 15; - - /* - * Malaysia 433mhz - */ - MY_433 = 16; - - /* - * Malaysia 919mhz - */ - MY_919 = 17; - - /* - * Singapore 923mhz - */ - SG_923 = 18; - - /* - * Philippines 433mhz - */ - PH_433 = 19; - - /* - * Philippines 868mhz - */ - PH_868 = 20; - - /* - * Philippines 915mhz - */ - PH_915 = 21; - } - - /* - * Standard predefined channel settings - * Note: these mappings must match ModemPreset Choice in the device code. - */ - enum ModemPreset { - /* - * Long Range - Fast - */ - LONG_FAST = 0; - - /* - * Long Range - Slow - */ - LONG_SLOW = 1; - - /* - * Very Long Range - Slow - */ - VERY_LONG_SLOW = 2; - - /* - * Medium Range - Slow - */ - MEDIUM_SLOW = 3; - - /* - * Medium Range - Fast - */ - MEDIUM_FAST = 4; - - /* - * Short Range - Slow - */ - SHORT_SLOW = 5; - - /* - * Short Range - Fast - */ - SHORT_FAST = 6; - - /* - * Long Range - Moderately Fast - */ - LONG_MODERATE = 7; - - /* - * Short Range - Turbo - * This is the fastest preset and the only one with 500kHz bandwidth. - * It is not legal to use in all regions due to this wider bandwidth. - */ - SHORT_TURBO = 8; - } - - /* - * When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate` - * will be taked from their respective manually defined fields - */ - bool use_preset = 1; - - /* - * Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH. - * As a heuristic: If bandwidth is specified, do not use modem_config. - * Because protobufs take ZERO space when the value is zero this works out nicely. - * This value is replaced by bandwidth/spread_factor/coding_rate. - * If you'd like to experiment with other options add them to MeshRadio.cpp in the device code. - */ - ModemPreset modem_preset = 2; - - /* - * Bandwidth in MHz - * Certain bandwidth numbers are 'special' and will be converted to the - * appropriate floating point value: 31 -> 31.25MHz - */ - uint32 bandwidth = 3; - - /* - * A number from 7 to 12. - * Indicates number of chirps per symbol as 1< 7 results in the default - */ - uint32 hop_limit = 8; - - /* - * Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests. - * Defaults to false - */ - bool tx_enabled = 9; - - /* - * If zero, then use default max legal continuous power (ie. something that won't - * burn out the radio hardware) - * In most cases you should use zero here. - * Units are in dBm. - */ - int32 tx_power = 10; - - /* - * This controls the actual hardware frequency the radio transmits on. - * Most users should never need to be exposed to this field/concept. - * A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region). - * If ZERO then the rule is "use the old channel name hash based - * algorithm to derive the channel number") - * If using the hash algorithm the channel number will be: hash(channel_name) % - * NUM_CHANNELS (Where num channels depends on the regulatory region). - */ - uint32 channel_num = 11; - - /* - * If true, duty cycle limits will be exceeded and thus you're possibly not following - * the local regulations if you're not a HAM. - * Has no effect if the duty cycle of the used region is 100%. - */ - bool override_duty_cycle = 12; - - /* - * If true, sets RX boosted gain mode on SX126X based radios - */ - bool sx126x_rx_boosted_gain = 13; - - /* - * This parameter is for advanced users and licensed HAM radio operators. - * Ignore Channel Calculation and use this frequency instead. The frequency_offset - * will still be applied. This will allow you to use out-of-band frequencies. - * Please respect your local laws and regulations. If you are a HAM, make sure you - * enable HAM mode and turn off encryption. - */ - float override_frequency = 14; - - /* - * For testing it is useful sometimes to force a node to never listen to - * particular other nodes (simulating radio out of range). All nodenums listed - * in ignore_incoming will have packets they send dropped on receive (by router.cpp) - */ - repeated uint32 ignore_incoming = 103; - - /* - * If true, the device will not process any packets received via LoRa that passed via MQTT anywhere on the path towards it. - */ - bool ignore_mqtt = 104; - } - - message BluetoothConfig { - enum PairingMode { - /* - * Device generates a random PIN that will be shown on the screen of the device for pairing - */ - RANDOM_PIN = 0; - - /* - * Device requires a specified fixed PIN for pairing - */ - FIXED_PIN = 1; - - /* - * Device requires no PIN for pairing - */ - NO_PIN = 2; - } - - /* - * Enable Bluetooth on the device - */ - bool enabled = 1; - - /* - * Determines the pairing strategy for the device - */ - PairingMode mode = 2; - - /* - * Specified PIN for PairingMode.FixedPin - */ - uint32 fixed_pin = 3; - } - - /* - * Payload Variant - */ - oneof payload_variant { - DeviceConfig device = 1; - PositionConfig position = 2; - PowerConfig power = 3; - NetworkConfig network = 4; - DisplayConfig display = 5; - LoRaConfig lora = 6; - BluetoothConfig bluetooth = 7; - } -} diff --git a/src/protos/meshtastic/connection_status.options b/src/protos/meshtastic/connection_status.options deleted file mode 100644 index d4901dd..0000000 --- a/src/protos/meshtastic/connection_status.options +++ /dev/null @@ -1 +0,0 @@ -*WifiConnectionStatus.ssid max_size:33 diff --git a/src/protos/meshtastic/connection_status.proto b/src/protos/meshtastic/connection_status.proto deleted file mode 100644 index 7551596..0000000 --- a/src/protos/meshtastic/connection_status.proto +++ /dev/null @@ -1,120 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ConnStatusProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -message DeviceConnectionStatus { - /* - * WiFi Status - */ - optional WifiConnectionStatus wifi = 1; - /* - * WiFi Status - */ - optional EthernetConnectionStatus ethernet = 2; - - /* - * Bluetooth Status - */ - optional BluetoothConnectionStatus bluetooth = 3; - - /* - * Serial Status - */ - optional SerialConnectionStatus serial = 4; -} - -/* - * WiFi connection status - */ -message WifiConnectionStatus { - /* - * Connection status - */ - NetworkConnectionStatus status = 1; - - /* - * WiFi access point SSID - */ - string ssid = 2; - - /* - * RSSI of wireless connection - */ - int32 rssi = 3; -} - -/* - * Ethernet connection status - */ -message EthernetConnectionStatus { - /* - * Connection status - */ - NetworkConnectionStatus status = 1; -} - -/* - * Ethernet or WiFi connection status - */ -message NetworkConnectionStatus { - /* - * IP address of device - */ - fixed32 ip_address = 1; - - /* - * Whether the device has an active connection or not - */ - bool is_connected = 2; - - /* - * Whether the device has an active connection to an MQTT broker or not - */ - bool is_mqtt_connected = 3; - - /* - * Whether the device is actively remote syslogging or not - */ - bool is_syslog_connected = 4; -} - -/* - * Bluetooth connection status - */ -message BluetoothConnectionStatus { - /* - * The pairing PIN for bluetooth - */ - uint32 pin = 1; - - /* - * RSSI of bluetooth connection - */ - int32 rssi = 2; - - /* - * Whether the device has an active connection or not - */ - bool is_connected = 3; -} - -/* - * Serial connection status - */ -message SerialConnectionStatus { - /* - * Serial baud rate - */ - uint32 baud = 1; - - /* - * Whether the device has an active connection or not - */ - bool is_connected = 2; -} diff --git a/src/protos/meshtastic/deviceonly.options b/src/protos/meshtastic/deviceonly.options deleted file mode 100644 index d870ace..0000000 --- a/src/protos/meshtastic/deviceonly.options +++ /dev/null @@ -1,19 +0,0 @@ -# options for nanopb -# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options - -# FIXME pick a higher number someday? or do dynamic alloc in nanopb? -*DeviceState.node_db_lite max_count:100 - -# FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in RAM -*DeviceState.receive_queue max_count:1 - -*ChannelFile.channels max_count:8 - -*OEMStore.oem_text max_size:40 -*OEMStore.oem_icon_bits max_size:2048 -*OEMStore.oem_aes_key max_size:32 - -*DeviceState.node_remote_hardware_pins max_count:12 - -*NodeInfoLite.channel int_size:8 -*NodeInfoLite.hops_away int_size:8 \ No newline at end of file diff --git a/src/protos/meshtastic/deviceonly.proto b/src/protos/meshtastic/deviceonly.proto deleted file mode 100644 index 169df1c..0000000 --- a/src/protos/meshtastic/deviceonly.proto +++ /dev/null @@ -1,262 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/channel.proto"; -import "meshtastic/localonly.proto"; -import "meshtastic/mesh.proto"; -import "meshtastic/telemetry.proto"; -import "meshtastic/module_config.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "DeviceOnly"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This message is never sent over the wire, but it is used for serializing DB - * state to flash in the device code - * FIXME, since we write this each time we enter deep sleep (and have infinite - * flash) it would be better to use some sort of append only data structure for - * the receive queue and use the preferences store for the other stuff - */ -message DeviceState { - /* - * Read only settings/info about this node - */ - MyNodeInfo my_node = 2; - - /* - * My owner info - */ - User owner = 3; - - /* - * Received packets saved for delivery to the phone - */ - repeated MeshPacket receive_queue = 5; - - /* - * A version integer used to invalidate old save files when we make - * incompatible changes This integer is set at build time and is private to - * NodeDB.cpp in the device code. - */ - uint32 version = 8; - - /* - * We keep the last received text message (only) stored in the device flash, - * so we can show it on the screen. - * Might be null - */ - MeshPacket rx_text_message = 7; - - /* - * Used only during development. - * Indicates developer is testing and changes should never be saved to flash. - */ - bool no_save = 9; - - /* - * Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. - */ - bool did_gps_reset = 11; - - /* - * We keep the last received waypoint stored in the device flash, - * so we can show it on the screen. - * Might be null - */ - MeshPacket rx_waypoint = 12; - - /* - * The mesh's nodes with their available gpio pins for RemoteHardware module - */ - repeated NodeRemoteHardwarePin node_remote_hardware_pins = 13; - - /* - * New lite version of NodeDB to decrease memory footprint - */ - repeated NodeInfoLite node_db_lite = 14; -} - -message NodeInfoLite { - /* - * The node number - */ - uint32 num = 1; - - /* - * The user info for this node - */ - User user = 2; - - /* - * This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true. - * Position.time now indicates the last time we received a POSITION from that node. - */ - PositionLite position = 3; - - /* - * Returns the Signal-to-noise ratio (SNR) of the last received message, - * as measured by the receiver. Return SNR of the last received message in dB - */ - float snr = 4; - - /* - * Set to indicate the last time we received a packet from this node - */ - fixed32 last_heard = 5; - /* - * The latest device metrics for the node. - */ - DeviceMetrics device_metrics = 6; - - /* - * local channel index we heard that node on. Only populated if its not the default channel. - */ - uint32 channel = 7; - - /* - * True if we witnessed the node over MQTT instead of LoRA transport - */ - bool via_mqtt = 8; - - /* - * Number of hops away from us this node is (0 if adjacent) - */ - uint32 hops_away = 9; -} - -/* - * Position with static location information only for NodeDBLite - */ -message PositionLite { - /* - * The new preferred location encoding, multiply by 1e-7 to get degrees - * in floating point - */ - sfixed32 latitude_i = 1; - - /* - * TODO: REPLACE - */ - sfixed32 longitude_i = 2; - - /* - * In meters above MSL (but see issue #359) - */ - int32 altitude = 3; - - /* - * This is usually not sent over the mesh (to save space), but it is sent - * from the phone so that the local device can set its RTC If it is sent over - * the mesh (because there are devices on the mesh without GPS), it will only - * be sent by devices which has a hardware GPS clock. - * seconds since 1970 - */ - fixed32 time = 4; - - /* - * TODO: REPLACE - */ - Position.LocSource location_source = 5; -} - -/* - * The on-disk saved channels - */ -message ChannelFile { - /* - * The channels our node knows about - */ - repeated Channel channels = 1; - - /* - * A version integer used to invalidate old save files when we make - * incompatible changes This integer is set at build time and is private to - * NodeDB.cpp in the device code. - */ - uint32 version = 2; -} - -/* - * TODO: REPLACE - */ -enum ScreenFonts { - /* - * TODO: REPLACE - */ - FONT_SMALL = 0; - - /* - * TODO: REPLACE - */ - FONT_MEDIUM = 1; - - /* - * TODO: REPLACE - */ - FONT_LARGE = 2; -} - -/* - * This can be used for customizing the firmware distribution. If populated, - * show a secondary bootup screen with custom logo and text for 2.5 seconds. - */ -message OEMStore { - /* - * The Logo width in Px - */ - uint32 oem_icon_width = 1; - - /* - * The Logo height in Px - */ - uint32 oem_icon_height = 2; - - /* - * The Logo in XBM bytechar format - */ - bytes oem_icon_bits = 3; - - /* - * Use this font for the OEM text. - */ - ScreenFonts oem_font = 4; - - /* - * Use this font for the OEM text. - */ - string oem_text = 5; - - /* - * The default device encryption key, 16 or 32 byte - */ - bytes oem_aes_key = 6; - - /* - * A Preset LocalConfig to apply during factory reset - */ - LocalConfig oem_local_config = 7; - - /* - * A Preset LocalModuleConfig to apply during factory reset - */ - LocalModuleConfig oem_local_module_config = 8; -} - -/* - * RemoteHardwarePins associated with a node - */ -message NodeRemoteHardwarePin { - /* - * The node_num exposing the available gpio pin - */ - uint32 node_num = 1; - - /* - * The the available gpio pin for usage with RemoteHardware module - */ - RemoteHardwarePin pin = 2; -} \ No newline at end of file diff --git a/src/protos/meshtastic/localonly.proto b/src/protos/meshtastic/localonly.proto deleted file mode 100644 index 9297dff..0000000 --- a/src/protos/meshtastic/localonly.proto +++ /dev/null @@ -1,135 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/config.proto"; -import "meshtastic/module_config.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "LocalOnlyProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * Protobuf structures common to apponly.proto and deviceonly.proto - * This is never sent over the wire, only for local use - */ - -message LocalConfig { - /* - * The part of the config that is specific to the Device - */ - Config.DeviceConfig device = 1; - - /* - * The part of the config that is specific to the GPS Position - */ - Config.PositionConfig position = 2; - - /* - * The part of the config that is specific to the Power settings - */ - Config.PowerConfig power = 3; - - /* - * The part of the config that is specific to the Wifi Settings - */ - Config.NetworkConfig network = 4; - - /* - * The part of the config that is specific to the Display - */ - Config.DisplayConfig display = 5; - - /* - * The part of the config that is specific to the Lora Radio - */ - Config.LoRaConfig lora = 6; - - /* - * The part of the config that is specific to the Bluetooth settings - */ - Config.BluetoothConfig bluetooth = 7; - - /* - * A version integer used to invalidate old save files when we make - * incompatible changes This integer is set at build time and is private to - * NodeDB.cpp in the device code. - */ - uint32 version = 8; -} - -message LocalModuleConfig { - /* - * The part of the config that is specific to the MQTT module - */ - ModuleConfig.MQTTConfig mqtt = 1; - - /* - * The part of the config that is specific to the Serial module - */ - ModuleConfig.SerialConfig serial = 2; - - /* - * The part of the config that is specific to the ExternalNotification module - */ - ModuleConfig.ExternalNotificationConfig external_notification = 3; - - /* - * The part of the config that is specific to the Store & Forward module - */ - ModuleConfig.StoreForwardConfig store_forward = 4; - - /* - * The part of the config that is specific to the RangeTest module - */ - ModuleConfig.RangeTestConfig range_test = 5; - - /* - * The part of the config that is specific to the Telemetry module - */ - ModuleConfig.TelemetryConfig telemetry = 6; - - /* - * The part of the config that is specific to the Canned Message module - */ - ModuleConfig.CannedMessageConfig canned_message = 7; - - /* - * The part of the config that is specific to the Audio module - */ - ModuleConfig.AudioConfig audio = 9; - - /* - * The part of the config that is specific to the Remote Hardware module - */ - ModuleConfig.RemoteHardwareConfig remote_hardware = 10; - - /* - * The part of the config that is specific to the Neighbor Info module - */ - ModuleConfig.NeighborInfoConfig neighbor_info = 11; - - /* - * The part of the config that is specific to the Ambient Lighting module - */ - ModuleConfig.AmbientLightingConfig ambient_lighting = 12; - - /* - * The part of the config that is specific to the Detection Sensor module - */ - ModuleConfig.DetectionSensorConfig detection_sensor = 13; - - /* - * Paxcounter Config - */ - ModuleConfig.PaxcounterConfig paxcounter = 14; - - /* - * A version integer used to invalidate old save files when we make - * incompatible changes This integer is set at build time and is private to - * NodeDB.cpp in the device code. - */ - uint32 version = 8; -} \ No newline at end of file diff --git a/src/protos/meshtastic/mesh.options b/src/protos/meshtastic/mesh.options deleted file mode 100644 index aedfe99..0000000 --- a/src/protos/meshtastic/mesh.options +++ /dev/null @@ -1,61 +0,0 @@ -# options for nanopb -# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options - -*macaddr max_size:6 fixed_length:true # macaddrs -*id max_size:16 # node id strings - -*User.long_name max_size:40 -*User.short_name max_size:5 - -*RouteDiscovery.route max_count:8 - -# note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is -# outside of this envelope -*Data.payload max_size:237 - -*NodeInfo.channel int_size:8 -*NodeInfo.hops_away int_size:8 - -# Big enough for 1.2.28.568032c-d -*MyNodeInfo.firmware_version max_size:18 - -*MyNodeInfo.air_period_tx max_count:8 -*MyNodeInfo.air_period_rx max_count:8 - -# Note: the actual limit (because of header bytes) on the size of encrypted payloads is 251 bytes, but I use 256 -# here because we might need to fill with zeros for padding to encryption block size (16 bytes per block) -*MeshPacket.encrypted max_size:256 -*MeshPacket.payload_variant anonymous_oneof:true -*MeshPacket.hop_limit int_size:8 -*MeshPacket.hop_start int_size:8 -*MeshPacket.channel int_size:8 - -*QueueStatus.res int_size:8 -*QueueStatus.free int_size:8 -*QueueStatus.maxlen int_size:8 - -*ToRadio.payload_variant anonymous_oneof:true - -*FromRadio.payload_variant anonymous_oneof:true - -*Routing.variant anonymous_oneof:true - -*LogRecord.message max_size:64 -*LogRecord.source max_size:8 - -# MyMessage.name max_size:40 -# or fixed_length or fixed_count, or max_count - -#This value may want to be a few bytes smaller to compensate for the parent fields. -*Compressed.data max_size:237 - -*Waypoint.name max_size:30 -*Waypoint.description max_size:100 - -*NeighborInfo.neighbors max_count:10 - -*DeviceMetadata.firmware_version max_size:18 - -*MqttClientProxyMessage.topic max_size:60 -*MqttClientProxyMessage.data max_size:435 -*MqttClientProxyMessage.text max_size:435 diff --git a/src/protos/meshtastic/mesh.proto b/src/protos/meshtastic/mesh.proto deleted file mode 100644 index 7f8b7e5..0000000 --- a/src/protos/meshtastic/mesh.proto +++ /dev/null @@ -1,1943 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/channel.proto"; -import "meshtastic/config.proto"; -import "meshtastic/module_config.proto"; -import "meshtastic/portnums.proto"; -import "meshtastic/telemetry.proto"; -import "meshtastic/xmodem.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "MeshProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * a gps position - */ -message Position { - /* - * The new preferred location encoding, multiply by 1e-7 to get degrees - * in floating point - */ - optional sfixed32 latitude_i = 1; - - /* - * TODO: REPLACE - */ - optional sfixed32 longitude_i = 2; - - /* - * In meters above MSL (but see issue #359) - */ - optional int32 altitude = 3; - - /* - * This is usually not sent over the mesh (to save space), but it is sent - * from the phone so that the local device can set its time if it is sent over - * the mesh (because there are devices on the mesh without GPS or RTC). - * seconds since 1970 - */ - fixed32 time = 4; - - /* - * How the location was acquired: manual, onboard GPS, external (EUD) GPS - */ - enum LocSource { - /* - * TODO: REPLACE - */ - LOC_UNSET = 0; - - /* - * TODO: REPLACE - */ - LOC_MANUAL = 1; - - /* - * TODO: REPLACE - */ - LOC_INTERNAL = 2; - - /* - * TODO: REPLACE - */ - LOC_EXTERNAL = 3; - } - - /* - * TODO: REPLACE - */ - LocSource location_source = 5; - - /* - * How the altitude was acquired: manual, GPS int/ext, etc - * Default: same as location_source if present - */ - enum AltSource { - /* - * TODO: REPLACE - */ - ALT_UNSET = 0; - - /* - * TODO: REPLACE - */ - ALT_MANUAL = 1; - - /* - * TODO: REPLACE - */ - ALT_INTERNAL = 2; - - /* - * TODO: REPLACE - */ - ALT_EXTERNAL = 3; - - /* - * TODO: REPLACE - */ - ALT_BAROMETRIC = 4; - } - - /* - * TODO: REPLACE - */ - AltSource altitude_source = 6; - - /* - * Positional timestamp (actual timestamp of GPS solution) in integer epoch seconds - */ - fixed32 timestamp = 7; - - /* - * Pos. timestamp milliseconds adjustment (rarely available or required) - */ - int32 timestamp_millis_adjust = 8; - - /* - * HAE altitude in meters - can be used instead of MSL altitude - */ - optional sint32 altitude_hae = 9; - - /* - * Geoidal separation in meters - */ - optional sint32 altitude_geoidal_separation = 10; - - /* - * Horizontal, Vertical and Position Dilution of Precision, in 1/100 units - * - PDOP is sufficient for most cases - * - for higher precision scenarios, HDOP and VDOP can be used instead, - * in which case PDOP becomes redundant (PDOP=sqrt(HDOP^2 + VDOP^2)) - * TODO: REMOVE/INTEGRATE - */ - uint32 PDOP = 11; - - /* - * TODO: REPLACE - */ - uint32 HDOP = 12; - - /* - * TODO: REPLACE - */ - uint32 VDOP = 13; - - /* - * GPS accuracy (a hardware specific constant) in mm - * multiplied with DOP to calculate positional accuracy - * Default: "'bout three meters-ish" :) - */ - uint32 gps_accuracy = 14; - - /* - * Ground speed in m/s and True North TRACK in 1/100 degrees - * Clarification of terms: - * - "track" is the direction of motion (measured in horizontal plane) - * - "heading" is where the fuselage points (measured in horizontal plane) - * - "yaw" indicates a relative rotation about the vertical axis - * TODO: REMOVE/INTEGRATE - */ - optional uint32 ground_speed = 15; - - /* - * TODO: REPLACE - */ - optional uint32 ground_track = 16; - - /* - * GPS fix quality (from NMEA GxGGA statement or similar) - */ - uint32 fix_quality = 17; - - /* - * GPS fix type 2D/3D (from NMEA GxGSA statement) - */ - uint32 fix_type = 18; - - /* - * GPS "Satellites in View" number - */ - uint32 sats_in_view = 19; - - /* - * Sensor ID - in case multiple positioning sensors are being used - */ - uint32 sensor_id = 20; - - /* - * Estimated/expected time (in seconds) until next update: - * - if we update at fixed intervals of X seconds, use X - * - if we update at dynamic intervals (based on relative movement etc), - * but "AT LEAST every Y seconds", use Y - */ - uint32 next_update = 21; - - /* - * A sequence number, incremented with each Position message to help - * detect lost updates if needed - */ - uint32 seq_number = 22; - - /* - * Indicates the bits of precision set by the sending node - */ - uint32 precision_bits = 23; -} - -/* - * Note: these enum names must EXACTLY match the string used in the device - * bin/build-all.sh script. - * Because they will be used to find firmware filenames in the android app for OTA updates. - * To match the old style filenames, _ is converted to -, p is converted to . - */ -enum HardwareModel { - /* - * TODO: REPLACE - */ - UNSET = 0; - - /* - * TODO: REPLACE - */ - TLORA_V2 = 1; - - /* - * TODO: REPLACE - */ - TLORA_V1 = 2; - - /* - * TODO: REPLACE - */ - TLORA_V2_1_1P6 = 3; - - /* - * TODO: REPLACE - */ - TBEAM = 4; - - /* - * The original heltec WiFi_Lora_32_V2, which had battery voltage sensing hooked to GPIO 13 - * (see HELTEC_V2 for the new version). - */ - HELTEC_V2_0 = 5; - - /* - * TODO: REPLACE - */ - TBEAM_V0P7 = 6; - - /* - * TODO: REPLACE - */ - T_ECHO = 7; - - /* - * TODO: REPLACE - */ - TLORA_V1_1P3 = 8; - - /* - * TODO: REPLACE - */ - RAK4631 = 9; - - /* - * The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37. - * Sadly they did not update anything on the silkscreen to identify this board - */ - HELTEC_V2_1 = 10; - - /* - * Ancient heltec WiFi_Lora_32 board - */ - HELTEC_V1 = 11; - - /* - * New T-BEAM with ESP32-S3 CPU - */ - LILYGO_TBEAM_S3_CORE = 12; - - /* - * RAK WisBlock ESP32 core: https://docs.rakwireless.com/Product-Categories/WisBlock/RAK11200/Overview/ - */ - RAK11200 = 13; - - /* - * B&Q Consulting Nano Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:nano - */ - NANO_G1 = 14; - - /* - * TODO: REPLACE - */ - TLORA_V2_1_1P8 = 15; - - /* - * TODO: REPLACE - */ - TLORA_T3_S3 = 16; - - /* - * B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer - */ - NANO_G1_EXPLORER = 17; - - /* - * B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra - */ - NANO_G2_ULTRA = 18; - - /* - * LoRAType device: https://loratype.org/ - */ - LORA_TYPE = 19; - - /* - * wiphone https://www.wiphone.io/ - */ - WIPHONE = 20; - - /* - * WIO Tracker WM1110 family from Seeed Studio. Includes wio-1110-tracker and wio-1110-sdk - */ - WIO_WM1110 = 21; - - /* - * RAK2560 Solar base station based on RAK4630 - */ - RAK2560 = 22; - - /* - * Heltec HRU-3601: https://heltec.org/project/hru-3601/ - */ - HELTEC_HRU_3601 = 23; - - /* - * Heltec Wireless Bridge - */ - HELTEC_WIRELESS_BRIDGE = 24; - - /* - * B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station - */ - STATION_G1 = 25; - - /* - * RAK11310 (RP2040 + SX1262) - */ - RAK11310 = 26; - - /* - * Makerfabs SenseLoRA Receiver (RP2040 + RFM96) - */ - SENSELORA_RP2040 = 27; - - /* - * Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96) - */ - SENSELORA_S3 = 28; - - /* - * Canary Radio Company - CanaryOne: https://canaryradio.io/products/canaryone - */ - CANARYONE = 29; - - /* - * Waveshare RP2040 LoRa - https://www.waveshare.com/rp2040-lora.htm - */ - RP2040_LORA = 30; - - /* - * B&Q Consulting Station G2: https://wiki.uniteng.com/en/meshtastic/station-g2 - */ - STATION_G2 = 31; - - /* - * --------------------------------------------------------------------------- - * Less common/prototype boards listed here (needs one more byte over the air) - * --------------------------------------------------------------------------- - */ - LORA_RELAY_V1 = 32; - - /* - * TODO: REPLACE - */ - NRF52840DK = 33; - - /* - * TODO: REPLACE - */ - PPR = 34; - - /* - * TODO: REPLACE - */ - GENIEBLOCKS = 35; - - /* - * TODO: REPLACE - */ - NRF52_UNKNOWN = 36; - - /* - * TODO: REPLACE - */ - PORTDUINO = 37; - - /* - * The simulator built into the android app - */ - ANDROID_SIM = 38; - - /* - * Custom DIY device based on @NanoVHF schematics: https://github.com/NanoVHF/Meshtastic-DIY/tree/main/Schematics - */ - DIY_V1 = 39; - - /* - * nRF52840 Dongle : https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle/ - */ - NRF52840_PCA10059 = 40; - - /* - * Custom Disaster Radio esp32 v3 device https://github.com/sudomesh/disaster-radio/tree/master/hardware/board_esp32_v3 - */ - DR_DEV = 41; - - /* - * M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ - */ - M5STACK = 42; - - /* - * New Heltec LoRA32 with ESP32-S3 CPU - */ - HELTEC_V3 = 43; - - /* - * New Heltec Wireless Stick Lite with ESP32-S3 CPU - */ - HELTEC_WSL_V3 = 44; - - /* - * New BETAFPV ELRS Micro TX Module 2.4G with ESP32 CPU - */ - BETAFPV_2400_TX = 45; - - /* - * BetaFPV ExpressLRS "Nano" TX Module 900MHz with ESP32 CPU - */ - BETAFPV_900_NANO_TX = 46; - - /* - * Raspberry Pi Pico (W) with Waveshare SX1262 LoRa Node Module - */ - RPI_PICO = 47; - - /* - * Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT - * Newer V1.1, version is written on the PCB near the display. - */ - HELTEC_WIRELESS_TRACKER = 48; - - /* - * Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display - */ - HELTEC_WIRELESS_PAPER = 49; - - /* - * LilyGo T-Deck with ESP32-S3 CPU, Keyboard and IPS display - */ - T_DECK = 50; - - /* - * LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display - */ - T_WATCH_S3 = 51; - - /* - * Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display - */ - PICOMPUTER_S3 = 52; - - /* - * Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa - */ - HELTEC_HT62 = 53; - - /* - * EBYTE SPI LoRa module and ESP32-S3 - */ - EBYTE_ESP32_S3 = 54; - - /* - * Waveshare ESP32-S3-PICO with PICO LoRa HAT and 2.9inch e-Ink - */ - ESP32_S3_PICO = 55; - - /* - * CircuitMess Chatter 2 LLCC68 Lora Module and ESP32 Wroom - * Lora module can be swapped out for a Heltec RA-62 which is "almost" pin compatible - * with one cut and one jumper Meshtastic works - */ - CHATTER_2 = 56; - - /* - * Heltec Wireless Paper, With ESP32-S3 CPU and E-Ink display - * Older "V1.0" Variant, has no "version sticker" - * E-Ink model is DEPG0213BNS800 - * Tab on the screen protector is RED - * Flex connector marking is FPC-7528B - */ - HELTEC_WIRELESS_PAPER_V1_0 = 57; - - /* - * Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT - * Older "V1.0" Variant - */ - HELTEC_WIRELESS_TRACKER_V1_0 = 58; - - /* - * unPhone with ESP32-S3, TFT touchscreen, LSM6DS3TR-C accelerometer and gyroscope - */ - UNPHONE = 59; - - /* - * Teledatics TD-LORAC NRF52840 based M.2 LoRA module - * Compatible with the TD-WRLS development board - */ - TD_LORAC = 60; - - /* - * CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 - */ - CDEBYTE_EORA_S3 = 61; - - /* - * TWC_MESH_V4 - * Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS - */ - TWC_MESH_V4 = 62; - - /* - * NRF52_PROMICRO_DIY - * Promicro NRF52840 with SX1262/LLCC68, SSD1306 OLED and NEO6M GPS - */ - NRF52_PROMICRO_DIY = 63; - - /* - * RadioMaster 900 Bandit Nano, https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module - * ESP32-D0WDQ6 With SX1276/SKY66122, SSD1306 OLED and No GPS - */ - RADIOMASTER_900_BANDIT_NANO = 64; - - /* - * Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors - */ - HELTEC_CAPSULE_SENSOR_V3 = 65; - - /* - * Heltec Vision Master T190 with ESP32-S3 CPU, and a 1.90 inch TFT display - */ - HELTEC_VISION_MASTER_T190 = 66; - - /* - * Heltec Vision Master E213 with ESP32-S3 CPU, and a 2.13 inch E-Ink display - */ - HELTEC_VISION_MASTER_E213 = 67; - - /* - * Heltec Vision Master E290 with ESP32-S3 CPU, and a 2.9 inch E-Ink display - */ - HELTEC_VISION_MASTER_E290 = 68; - - /* - * Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, - * specifically adapted for the Meshtatic project - */ - HELTEC_MESH_NODE_T114 = 69; - - /* - * Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor - */ - SENSECAP_INDICATOR = 70; - - /* - * Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. - */ - TRACKER_T1000_E = 71; - - /* - * RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) - */ - RAK3172 = 72; - - /* - * Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. - */ - WIO_E5 = 73; - - /* - * RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module - * SSD1306 OLED and No GPS - */ - RADIOMASTER_900_BANDIT = 74; - - /* - * Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. - */ - ME25LS01_4Y10TD = 75; - - /* - * RP2040_FEATHER_RFM95 - * Adafruit Feather RP2040 with RFM95 LoRa Radio RFM95 with SX1272, SSD1306 OLED - * https://www.adafruit.com/product/5714 - * https://www.adafruit.com/product/326 - * https://www.adafruit.com/product/938 - * ^^^ short A0 to switch to I2C address 0x3C - * - */ - RP2040_FEATHER_RFM95 = 76; - - /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */ - M5STACK_COREBASIC = 77; - M5STACK_CORE2 = 78; - - /* Pico2 with Waveshare Hat, same as Pico */ - RPI_PICO2 = 79; - - /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */ - M5STACK_CORES3 = 80; - - /* Seeed XIAO S3 DK*/ - SEEED_XIAO_S3 = 81; - - /* - * Nordic nRF52840+Semtech SX1262 LoRa BLE Combo Module. nRF52840+SX1262 MS24SF1 - */ - MS24SF1 = 82; - - /* - * Lilygo TLora-C6 with the new ESP32-C6 MCU - */ - TLORA_C6 = 83; - - /* - * WisMesh Tap - * RAK-4631 w/ TFT in injection modled case - */ - WISMESH_TAP = 84; - - /* - * Similar to PORTDUINO but used by Routastic devices, this is not any - * particular device and does not run Meshtastic's code but supports - * the same frame format. - * Runs on linux, see https://github.com/Jorropo/routastic - */ - ROUTASTIC = 85; - - /* - * Mesh-Tab, esp32 based - * https://github.com/valzzu/Mesh-Tab - */ - MESH_TAB = 86; - - /* - * ------------------------------------------------------------------------------------------------------------------------------------------ - * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. - * ------------------------------------------------------------------------------------------------------------------------------------------ - */ - PRIVATE_HW = 255; -} - -/* - * Broadcast when a newly powered mesh node wants to find a node num it can use - * Sent from the phone over bluetooth to set the user id for the owner of this node. - * Also sent from nodes to each other when a new node signs on (so all clients can have this info) - * The algorithm is as follows: - * when a node starts up, it broadcasts their user and the normal flow is for all - * other nodes to reply with their User as well (so the new node can build its nodedb) - * If a node ever receives a User (not just the first broadcast) message where - * the sender node number equals our node number, that indicates a collision has - * occurred and the following steps should happen: - * If the receiving node (that was already in the mesh)'s macaddr is LOWER than the - * new User who just tried to sign in: it gets to keep its nodenum. - * We send a broadcast message of OUR User (we use a broadcast so that the other node can - * receive our message, considering we have the same id - it also serves to let - * observers correct their nodedb) - this case is rare so it should be okay. - * If any node receives a User where the macaddr is GTE than their local macaddr, - * they have been vetoed and should pick a new random nodenum (filtering against - * whatever it knows about the nodedb) and rebroadcast their User. - * A few nodenums are reserved and will never be requested: - * 0xff - broadcast - * 0 through 3 - for future use - */ -message User { - /* - * A globally unique ID string for this user. - * In the case of Signal that would mean +16504442323, for the default macaddr derived id it would be !<8 hexidecimal bytes>. - * Note: app developers are encouraged to also use the following standard - * node IDs "^all" (for broadcast), "^local" (for the locally connected node) - */ - string id = 1; - - /* - * A full name for this user, i.e. "Kevin Hester" - */ - string long_name = 2; - - /* - * A VERY short name, ideally two characters. - * Suitable for a tiny OLED screen - */ - string short_name = 3; - - /* - * Deprecated in Meshtastic 2.1.x - * This is the addr of the radio. - * Not populated by the phone, but added by the esp32 when broadcasting - */ - bytes macaddr = 4 [deprecated = true]; - - /* - * TBEAM, HELTEC, etc... - * Starting in 1.2.11 moved to hw_model enum in the NodeInfo object. - * Apps will still need the string here for older builds - * (so OTA update can find the right image), but if the enum is available it will be used instead. - */ - HardwareModel hw_model = 5; - - /* - * In some regions Ham radio operators have different bandwidth limitations than others. - * If this user is a licensed operator, set this flag. - * Also, "long_name" should be their licence number. - */ - bool is_licensed = 6; - - /* - * Indicates that the user's role in the mesh - */ - Config.DeviceConfig.Role role = 7; - - /* - * The public key of the user's device. - * This is sent out to other nodes on the mesh to allow them to compute a shared secret key. - */ - bytes public_key = 8; -} - -/* - * A message used in a traceroute - */ -message RouteDiscovery { - /* - * The list of nodenums this packet has visited so far to the destination. - */ - repeated fixed32 route = 1; - - /* - * The list of SNRs (in dB, scaled by 4) in the route towards the destination. - */ - repeated int32 snr_towards = 2; - - /* - * The list of nodenums the packet has visited on the way back from the destination. - */ - repeated fixed32 route_back = 3; - - /* - * The list of SNRs (in dB, scaled by 4) in the route back from the destination. - */ - repeated int32 snr_back = 4; -} - -/* - * A Routing control Data packet handled by the routing module - */ -message Routing { - /* - * A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide - * details on the type of failure). - */ - enum Error { - /* - * This message is not a failure - */ - NONE = 0; - - /* - * Our node doesn't have a route to the requested destination anymore. - */ - NO_ROUTE = 1; - - /* - * We received a nak while trying to forward on your behalf - */ - GOT_NAK = 2; - - /* - * TODO: REPLACE - */ - TIMEOUT = 3; - - /* - * No suitable interface could be found for delivering this packet - */ - NO_INTERFACE = 4; - - /* - * We reached the max retransmission count (typically for naive flood routing) - */ - MAX_RETRANSMIT = 5; - - /* - * No suitable channel was found for sending this packet (i.e. was requested channel index disabled?) - */ - NO_CHANNEL = 6; - - /* - * The packet was too big for sending (exceeds interface MTU after encoding) - */ - TOO_LARGE = 7; - - /* - * The request had want_response set, the request reached the destination node, but no service on that node wants to send a response - * (possibly due to bad channel permissions) - */ - NO_RESPONSE = 8; - - /* - * Cannot send currently because duty cycle regulations will be violated. - */ - DUTY_CYCLE_LIMIT = 9; - - /* - * The application layer service on the remote node received your request, but considered your request somehow invalid - */ - BAD_REQUEST = 32; - - /* - * The application layer service on the remote node received your request, but considered your request not authorized - * (i.e you did not send the request on the required bound channel) - */ - NOT_AUTHORIZED = 33; - - /* - * The client specified a PKI transport, but the node was unable to send the packet using PKI (and did not send the message at all) - */ - PKI_FAILED = 34; - - /* - * The receiving node does not have a Public Key to decode with - */ - PKI_UNKNOWN_PUBKEY = 35; - } - - oneof variant { - /* - * A route request going from the requester - */ - RouteDiscovery route_request = 1; - - /* - * A route reply - */ - RouteDiscovery route_reply = 2; - - /* - * A failure in delivering a message (usually used for routing control messages, but might be provided - * in addition to ack.fail_id to provide details on the type of failure). - */ - Error error_reason = 3; - } -} - -/* - * (Formerly called SubPacket) - * The payload portion fo a packet, this is the actual bytes that are sent - * inside a radio packet (because from/to are broken out by the comms library) - */ -message Data { - /* - * Formerly named typ and of type Type - */ - PortNum portnum = 1; - - /* - * TODO: REPLACE - */ - bytes payload = 2; - - /* - * Not normally used, but for testing a sender can request that recipient - * responds in kind (i.e. if it received a position, it should unicast back it's position). - * Note: that if you set this on a broadcast you will receive many replies. - */ - bool want_response = 3; - - /* - * The address of the destination node. - * This field is is filled in by the mesh radio device software, application - * layer software should never need it. - * RouteDiscovery messages _must_ populate this. - * Other message types might need to if they are doing multihop routing. - */ - fixed32 dest = 4; - - /* - * The address of the original sender for this message. - * This field should _only_ be populated for reliable multihop packets (to keep - * packets small). - */ - fixed32 source = 5; - - /* - * Only used in routing or response messages. - * Indicates the original message ID that this message is reporting failure on. (formerly called original_id) - */ - fixed32 request_id = 6; - - /* - * If set, this message is intened to be a reply to a previously sent message with the defined id. - */ - fixed32 reply_id = 7; - - /* - * Defaults to false. If true, then what is in the payload should be treated as an emoji like giving - * a message a heart or poop emoji. - */ - fixed32 emoji = 8; - - /* - * Bitfield for extra flags. First use is to indicate that user approves the packet being uploaded to MQTT. - */ - optional uint32 bitfield = 9; -} - -/* - * Waypoint message, used to share arbitrary locations across the mesh - */ -message Waypoint { - /* - * Id of the waypoint - */ - uint32 id = 1; - - /* - * latitude_i - */ - optional sfixed32 latitude_i = 2; - - /* - * longitude_i - */ - optional sfixed32 longitude_i = 3; - - /* - * Time the waypoint is to expire (epoch) - */ - uint32 expire = 4; - - /* - * If greater than zero, treat the value as a nodenum only allowing them to update the waypoint. - * If zero, the waypoint is open to be edited by any member of the mesh. - */ - uint32 locked_to = 5; - - /* - * Name of the waypoint - max 30 chars - */ - string name = 6; - - /* - * Description of the waypoint - max 100 chars - */ - string description = 7; - - /* - * Designator icon for the waypoint in the form of a unicode emoji - */ - fixed32 icon = 8; -} - -/* - * This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server - */ -message MqttClientProxyMessage { - /* - * The MQTT topic this message will be sent /received on - */ - string topic = 1; - - /* - * The actual service envelope payload or text for mqtt pub / sub - */ - oneof payload_variant { - /* - * Bytes - */ - bytes data = 2; - - /* - * Text - */ - string text = 3; - } - - /* - * Whether the message should be retained (or not) - */ - bool retained = 4; -} - -/* - * A packet envelope sent/received over the mesh - * only payload_variant is sent in the payload portion of the LORA packet. - * The other fields are either not sent at all, or sent in the special 16 byte LORA header. - */ -message MeshPacket { - /* - * The priority of this message for sending. - * Higher priorities are sent first (when managing the transmit queue). - * This field is never sent over the air, it is only used internally inside of a local device node. - * API clients (either on the local node or connected directly to the node) - * can set this parameter if necessary. - * (values must be <= 127 to keep protobuf field to one byte in size. - * Detailed background on this field: - * I noticed a funny side effect of lora being so slow: Usually when making - * a protocol there isn’t much need to use message priority to change the order - * of transmission (because interfaces are fairly fast). - * But for lora where packets can take a few seconds each, it is very important - * to make sure that critical packets are sent ASAP. - * In the case of meshtastic that means we want to send protocol acks as soon as possible - * (to prevent unneeded retransmissions), we want routing messages to be sent next, - * then messages marked as reliable and finally 'background' packets like periodic position updates. - * So I bit the bullet and implemented a new (internal - not sent over the air) - * field in MeshPacket called 'priority'. - * And the transmission queue in the router object is now a priority queue. - */ - enum Priority { - /* - * Treated as Priority.DEFAULT - */ - UNSET = 0; - - /* - * TODO: REPLACE - */ - MIN = 1; - - /* - * Background position updates are sent with very low priority - - * if the link is super congested they might not go out at all - */ - BACKGROUND = 10; - - /* - * This priority is used for most messages that don't have a priority set - */ - DEFAULT = 64; - - /* - * If priority is unset but the message is marked as want_ack, - * assume it is important and use a slightly higher priority - */ - RELIABLE = 70; - - /* - * If priority is unset but the packet is a response to a request, we want it to get there relatively quickly. - * Furthermore, responses stop relaying packets directed to a node early. - */ - RESPONSE = 80; - - /* - * Higher priority for specific message types (portnums) to distinguish between other reliable packets. - */ - HIGH = 100; - - /* - * Ack/naks are sent with very high priority to ensure that retransmission - * stops as soon as possible - */ - ACK = 120; - - /* - * TODO: REPLACE - */ - MAX = 127; - } - - /* - * Identify if this is a delayed packet - */ - enum Delayed { - /* - * If unset, the message is being sent in real time. - */ - NO_DELAY = 0; - - /* - * The message is delayed and was originally a broadcast - */ - DELAYED_BROADCAST = 1; - - /* - * The message is delayed and was originally a direct message - */ - DELAYED_DIRECT = 2; - } - - /* - * The sending node number. - * Note: Our crypto implementation uses this field as well. - * See [crypto](/docs/overview/encryption) for details. - */ - fixed32 from = 1; - - /* - * The (immediate) destination for this packet - */ - fixed32 to = 2; - - /* - * (Usually) If set, this indicates the index in the secondary_channels table that this packet was sent/received on. - * If unset, packet was on the primary channel. - * A particular node might know only a subset of channels in use on the mesh. - * Therefore channel_index is inherently a local concept and meaningless to send between nodes. - * Very briefly, while sending and receiving deep inside the device Router code, this field instead - * contains the 'channel hash' instead of the index. - * This 'trick' is only used while the payload_variant is an 'encrypted'. - */ - uint32 channel = 3; - - /* - * Internally to the mesh radios we will route SubPackets encrypted per [this](docs/developers/firmware/encryption). - * However, when a particular node has the correct - * key to decode a particular packet, it will decode the payload into a SubPacket protobuf structure. - * Software outside of the device nodes will never encounter a packet where - * "decoded" is not populated (i.e. any encryption/decryption happens before reaching the applications) - * The numeric IDs for these fields were selected to keep backwards compatibility with old applications. - */ - - oneof payload_variant { - /* - * TODO: REPLACE - */ - Data decoded = 4; - - /* - * TODO: REPLACE - */ - bytes encrypted = 5; - } - - /* - * A unique ID for this packet. - * Always 0 for no-ack packets or non broadcast packets (and therefore take zero bytes of space). - * Otherwise a unique ID for this packet, useful for flooding algorithms. - * ID only needs to be unique on a _per sender_ basis, and it only - * needs to be unique for a few minutes (long enough to last for the length of - * any ACK or the completion of a mesh broadcast flood). - * Note: Our crypto implementation uses this id as well. - * See [crypto](/docs/overview/encryption) for details. - */ - fixed32 id = 6; - - /* - * The time this message was received by the esp32 (secs since 1970). - * Note: this field is _never_ sent on the radio link itself (to save space) Times - * are typically not sent over the mesh, but they will be added to any Packet - * (chain of SubPacket) sent to the phone (so the phone can know exact time of reception) - */ - fixed32 rx_time = 7; - - /* - * *Never* sent over the radio links. - * Set during reception to indicate the SNR of this packet. - * Used to collect statistics on current link quality. - */ - float rx_snr = 8; - - /* - * If unset treated as zero (no forwarding, send to adjacent nodes only) - * if 1, allow hopping through one node, etc... - * For our usecase real world topologies probably have a max of about 3. - * This field is normally placed into a few of bits in the header. - */ - uint32 hop_limit = 9; - - /* - * This packet is being sent as a reliable message, we would prefer it to arrive at the destination. - * We would like to receive a ack packet in response. - * Broadcasts messages treat this flag specially: Since acks for broadcasts would - * rapidly flood the channel, the normal ack behavior is suppressed. - * Instead, the original sender listens to see if at least one node is rebroadcasting this packet (because naive flooding algorithm). - * If it hears that the odds (given typical LoRa topologies) the odds are very high that every node should eventually receive the message. - * So FloodingRouter.cpp generates an implicit ack which is delivered to the original sender. - * If after some time we don't hear anyone rebroadcast our packet, we will timeout and retransmit, using the regular resend logic. - * Note: This flag is normally sent in a flag bit in the header when sent over the wire - */ - bool want_ack = 10; - - /* - * The priority of this message for sending. - * See MeshPacket.Priority description for more details. - */ - Priority priority = 11; - - /* - * rssi of received packet. Only sent to phone for dispay purposes. - */ - int32 rx_rssi = 12; - - /* - * Describe if this message is delayed - */ - Delayed delayed = 13 [deprecated = true]; - - /* - * Describes whether this packet passed via MQTT somewhere along the path it currently took. - */ - bool via_mqtt = 14; - - /* - * Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header. - * When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled. - */ - uint32 hop_start = 15; - - /* - * Records the public key the packet was encrypted with, if applicable. - */ - bytes public_key = 16; - - /* - * Indicates whether the packet was en/decrypted using PKI - */ - bool pki_encrypted = 17; -} - -/* - * Shared constants between device and phone - */ -enum Constants { - /* - * First enum must be zero, and we are just using this enum to - * pass int constants between two very different environments - */ - ZERO = 0; - - /* - * From mesh.options - * note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is - * outside of this envelope - */ - DATA_PAYLOAD_LEN = 237; -} - -/* - * The bluetooth to device link: - * Old BTLE protocol docs from TODO, merge in above and make real docs... - * use protocol buffers, and NanoPB - * messages from device to phone: - * POSITION_UPDATE (..., time) - * TEXT_RECEIVED(from, text, time) - * OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications) - * messages from phone to device: - * SET_MYID(id, human readable long, human readable short) (send down the unique ID - * string used for this node, a human readable string shown for that id, and a very - * short human readable string suitable for oled screen) SEND_OPAQUE(dest, payload) - * (for signal messages or other applications) SEND_TEXT(dest, text) Get all - * nodes() (returns list of nodes, with full info, last time seen, loc, battery - * level etc) SET_CONFIG (switches device to a new set of radio params and - * preshared key, drops all existing nodes, force our node to rejoin this new group) - * Full information about a node on the mesh - */ -message NodeInfo { - /* - * The node number - */ - uint32 num = 1; - - /* - * The user info for this node - */ - User user = 2; - - /* - * This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true. - * Position.time now indicates the last time we received a POSITION from that node. - */ - Position position = 3; - - /* - * Returns the Signal-to-noise ratio (SNR) of the last received message, - * as measured by the receiver. Return SNR of the last received message in dB - */ - float snr = 4; - - /* - * TODO: REMOVE/INTEGRATE - * Returns the last measured frequency error. - * The LoRa receiver estimates the frequency offset between the receiver - * center frequency and that of the received LoRa signal. This function - * returns the estimates offset (in Hz) of the last received message. - * Caution: this measurement is not absolute, but is measured relative to the - * local receiver's oscillator. Apparent errors may be due to the - * transmitter, the receiver or both. \return The estimated center frequency - * offset in Hz of the last received message. - * int32 frequency_error = 6; - * enum RouteState { - * Invalid = 0; - * Discovering = 1; - * Valid = 2; - * } - * Not needed? - * RouteState route = 4; - */ - - /* - * TODO: REMOVE/INTEGRATE - * Not currently used (till full DSR deployment?) Our current preferred node node for routing - might be the same as num if - * we are adjacent Or zero if we don't yet know a route to this node. - * fixed32 next_hop = 5; - */ - - /* - * Set to indicate the last time we received a packet from this node - */ - fixed32 last_heard = 5; - /* - * The latest device metrics for the node. - */ - DeviceMetrics device_metrics = 6; - - /* - * local channel index we heard that node on. Only populated if its not the default channel. - */ - uint32 channel = 7; - - /* - * True if we witnessed the node over MQTT instead of LoRA transport - */ - bool via_mqtt = 8; - - /* - * Number of hops away from us this node is (0 if adjacent) - */ - uint32 hops_away = 9; - - /* - * True if node is in our favorites list - * Persists between NodeDB internal clean ups - */ - bool is_favorite = 10; -} - -/* - * Error codes for critical errors - * The device might report these fault codes on the screen. - * If you encounter a fault code, please post on the meshtastic.discourse.group - * and we'll try to help. - */ -enum CriticalErrorCode { - /* - * TODO: REPLACE - */ - NONE = 0; - - /* - * A software bug was detected while trying to send lora - */ - TX_WATCHDOG = 1; - - /* - * A software bug was detected on entry to sleep - */ - SLEEP_ENTER_WAIT = 2; - - /* - * No Lora radio hardware could be found - */ - NO_RADIO = 3; - - /* - * Not normally used - */ - UNSPECIFIED = 4; - - /* - * We failed while configuring a UBlox GPS - */ - UBLOX_UNIT_FAILED = 5; - - /* - * This board was expected to have a power management chip and it is missing or broken - */ - NO_AXP192 = 6; - - /* - * The channel tried to set a radio setting which is not supported by this chipset, - * radio comms settings are now undefined. - */ - INVALID_RADIO_SETTING = 7; - - /* - * Radio transmit hardware failure. We sent data to the radio chip, but it didn't - * reply with an interrupt. - */ - TRANSMIT_FAILED = 8; - - /* - * We detected that the main CPU voltage dropped below the minimum acceptable value - */ - BROWNOUT = 9; - - /* Selftest of SX1262 radio chip failed */ - SX1262_FAILURE = 10; - - /* - * A (likely software but possibly hardware) failure was detected while trying to send packets. - * If this occurs on your board, please post in the forum so that we can ask you to collect some information to allow fixing this bug - */ - RADIO_SPI_BUG = 11; - - /* - * Corruption was detected on the flash filesystem but we were able to repair things. - * If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. - */ - FLASH_CORRUPTION_RECOVERABLE = 12; - - /* - * Corruption was detected on the flash filesystem but we were unable to repair things. - * NOTE: Your node will probably need to be reconfigured the next time it reboots (it will lose the region code etc...) - * If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. - */ - FLASH_CORRUPTION_UNRECOVERABLE = 13; -} - -/* - * Unique local debugging info for this node - * Note: we don't include position or the user info, because that will come in the - * Sent to the phone in response to WantNodes. - */ -message MyNodeInfo { - /* - * Tells the phone what our node number is, default starting value is - * lowbyte of macaddr, but it will be fixed if that is already in use - */ - uint32 my_node_num = 1; - - /* - * The total number of reboots this node has ever encountered - * (well - since the last time we discarded preferences) - */ - uint32 reboot_count = 8; - - /* - * The minimum app version that can talk to this device. - * Phone/PC apps should compare this to their build number and if too low tell the user they must update their app - */ - uint32 min_app_version = 11; -} - -/* - * Debug output from the device. - * To minimize the size of records inside the device code, if a time/source/level is not set - * on the message it is assumed to be a continuation of the previously sent message. - * This allows the device code to use fixed maxlen 64 byte strings for messages, - * and then extend as needed by emitting multiple records. - */ -message LogRecord { - /* - * Log levels, chosen to match python logging conventions. - */ - enum Level { - /* - * Log levels, chosen to match python logging conventions. - */ - UNSET = 0; - - /* - * Log levels, chosen to match python logging conventions. - */ - CRITICAL = 50; - - /* - * Log levels, chosen to match python logging conventions. - */ - ERROR = 40; - - /* - * Log levels, chosen to match python logging conventions. - */ - WARNING = 30; - - /* - * Log levels, chosen to match python logging conventions. - */ - INFO = 20; - - /* - * Log levels, chosen to match python logging conventions. - */ - DEBUG = 10; - - /* - * Log levels, chosen to match python logging conventions. - */ - TRACE = 5; - } - - /* - * Log levels, chosen to match python logging conventions. - */ - string message = 1; - - /* - * Seconds since 1970 - or 0 for unknown/unset - */ - fixed32 time = 2; - - /* - * Usually based on thread name - if known - */ - string source = 3; - - /* - * Not yet set - */ - Level level = 4; -} - -message QueueStatus { - /* Last attempt to queue status, ErrorCode */ - int32 res = 1; - - /* Free entries in the outgoing queue */ - uint32 free = 2; - - /* Maximum entries in the outgoing queue */ - uint32 maxlen = 3; - - /* What was mesh packet id that generated this response? */ - uint32 mesh_packet_id = 4; -} - -/* - * Packets from the radio to the phone will appear on the fromRadio characteristic. - * It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? - * It will sit in that descriptor until consumed by the phone, - * at which point the next item in the FIFO will be populated. - */ -message FromRadio { - /* - * The packet id, used to allow the phone to request missing read packets from the FIFO, - * see our bluetooth docs - */ - uint32 id = 1; - - /* - * Log levels, chosen to match python logging conventions. - */ - oneof payload_variant { - /* - * Log levels, chosen to match python logging conventions. - */ - MeshPacket packet = 2; - - /* - * Tells the phone what our node number is, can be -1 if we've not yet joined a mesh. - * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. - */ - MyNodeInfo my_info = 3; - - /* - * One packet is sent for each node in the on radio DB - * starts over with the first node in our DB - */ - NodeInfo node_info = 4; - - /* - * Include a part of the config (was: RadioConfig radio) - */ - Config config = 5; - - /* - * Set to send debug console output over our protobuf stream - */ - LogRecord log_record = 6; - - /* - * Sent as true once the device has finished sending all of the responses to want_config - * recipient should check if this ID matches our original request nonce, if - * not, it means your config responses haven't started yet. - * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. - */ - uint32 config_complete_id = 7; - - /* - * Sent to tell clients the radio has just rebooted. - * Set to true if present. - * Not used on all transports, currently just used for the serial console. - * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. - */ - bool rebooted = 8; - - /* - * Include module config - */ - ModuleConfig moduleConfig = 9; - - /* - * One packet is sent for each channel - */ - Channel channel = 10; - - /* - * Queue status info - */ - QueueStatus queueStatus = 11; - - /* - * File Transfer Chunk - */ - XModem xmodemPacket = 12; - - /* - * Device metadata message - */ - DeviceMetadata metadata = 13; - - /* - * MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) - */ - MqttClientProxyMessage mqttClientProxyMessage = 14; - - /* - * File system manifest messages - */ - FileInfo fileInfo = 15; - - /* - * Notification message to the client - */ - ClientNotification clientNotification = 16; - } -} - -/* - * A notification message from the device to the client - * To be used for important messages that should to be displayed to the user - * in the form of push notifications or validation messages when saving - * invalid configuration. - */ -message ClientNotification { - /* - * The id of the packet we're notifying in response to - */ - optional uint32 reply_id = 1; - - /* - * Seconds since 1970 - or 0 for unknown/unset - */ - fixed32 time = 2; - - /* - * The level type of notification - */ - LogRecord.Level level = 3; - /* - * The message body of the notification - */ - string message = 4; -} - -/* - * Individual File info for the device - */ -message FileInfo { - /* - * The fully qualified path of the file - */ - string file_name = 1; - - /* - * The size of the file in bytes - */ - uint32 size_bytes = 2; -} - -/* - * Packets/commands to the radio will be written (reliably) to the toRadio characteristic. - * Once the write completes the phone can assume it is handled. - */ -message ToRadio { - /* - * Log levels, chosen to match python logging conventions. - */ - oneof payload_variant { - /* - * Send this packet on the mesh - */ - MeshPacket packet = 1; - - /* - * Phone wants radio to send full node db to the phone, This is - * typically the first packet sent to the radio when the phone gets a - * bluetooth connection. The radio will respond by sending back a - * MyNodeInfo, a owner, a radio config and a series of - * FromRadio.node_infos, and config_complete - * the integer you write into this field will be reported back in the - * config_complete_id response this allows clients to never be confused by - * a stale old partially sent config. - */ - uint32 want_config_id = 3; - - /* - * Tell API server we are disconnecting now. - * This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link. - * (Sending this message is optional for clients) - */ - bool disconnect = 4; - - /* - * File Transfer Chunk - */ - - XModem xmodemPacket = 5; - - /* - * MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) - */ - MqttClientProxyMessage mqttClientProxyMessage = 6; - - /* - * Heartbeat message (used to keep the device connection awake on serial) - */ - Heartbeat heartbeat = 7; - } -} - -/* - * Compressed message payload - */ -message Compressed { - /* - * PortNum to determine the how to handle the compressed payload. - */ - PortNum portnum = 1; - - /* - * Compressed data. - */ - bytes data = 2; -} - -/* - * Full info on edges for a single node - */ -message NeighborInfo { - /* - * The node ID of the node sending info on its neighbors - */ - uint32 node_id = 1; - /* - * Field to pass neighbor info for the next sending cycle - */ - uint32 last_sent_by_id = 2; - - /* - * Broadcast interval of the represented node (in seconds) - */ - uint32 node_broadcast_interval_secs = 3; - /* - * The list of out edges from this node - */ - repeated Neighbor neighbors = 4; -} - -/* - * A single edge in the mesh - */ -message Neighbor { - /* - * Node ID of neighbor - */ - uint32 node_id = 1; - - /* - * SNR of last heard message - */ - float snr = 2; - - /* - * Reception time (in secs since 1970) of last message that was last sent by this ID. - * Note: this is for local storage only and will not be sent out over the mesh. - */ - fixed32 last_rx_time = 3; - - /* - * Broadcast interval of this neighbor (in seconds). - * Note: this is for local storage only and will not be sent out over the mesh. - */ - uint32 node_broadcast_interval_secs = 4; -} - -/* - * Device metadata response - */ -message DeviceMetadata { - /* - * Device firmware version string - */ - string firmware_version = 1; - - /* - * Device state version - */ - uint32 device_state_version = 2; - - /* - * Indicates whether the device can shutdown CPU natively or via power management chip - */ - bool canShutdown = 3; - - /* - * Indicates that the device has native wifi capability - */ - bool hasWifi = 4; - - /* - * Indicates that the device has native bluetooth capability - */ - bool hasBluetooth = 5; - - /* - * Indicates that the device has an ethernet peripheral - */ - bool hasEthernet = 6; - - /* - * Indicates that the device's role in the mesh - */ - Config.DeviceConfig.Role role = 7; - - /* - * Indicates the device's current enabled position flags - */ - uint32 position_flags = 8; - - /* - * Device hardware model - */ - HardwareModel hw_model = 9; - - /* - * Has Remote Hardware enabled - */ - bool hasRemoteHardware = 10; -} - -/* - * A heartbeat message is sent to the node from the client to keep the connection alive. - * This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. - */ -message Heartbeat {} - -/* - * RemoteHardwarePins associated with a node - */ -message NodeRemoteHardwarePin { - /* - * The node_num exposing the available gpio pin - */ - uint32 node_num = 1; - - /* - * The the available gpio pin for usage with RemoteHardware module - */ - RemoteHardwarePin pin = 2; -} - -message ChunkedPayload { - /* - * The ID of the entire payload - */ - uint32 payload_id = 1; - - /* - * The total number of chunks in the payload - */ - uint32 chunk_count = 2; - - /* - * The current chunk index in the total - */ - uint32 chunk_index = 3; - - /* - * The binary data of the current chunk - */ - bytes payload_chunk = 4; -} - -/* - * Wrapper message for broken repeated oneof support - */ -message resend_chunks { - repeated uint32 chunks = 1; -} - -/* - * Responses to a ChunkedPayload request - */ -message ChunkedPayloadResponse { - /* - * The ID of the entire payload - */ - uint32 payload_id = 1; - - oneof payload_variant { - /* - * Request to transfer chunked payload - */ - bool request_transfer = 2; - - /* - * Accept the transfer chunked payload - */ - bool accept_transfer = 3; - /* - * Request missing indexes in the chunked payload - */ - resend_chunks resend_chunks = 4; - } -} \ No newline at end of file diff --git a/src/protos/meshtastic/module_config.options b/src/protos/meshtastic/module_config.options deleted file mode 100644 index fdc46d5..0000000 --- a/src/protos/meshtastic/module_config.options +++ /dev/null @@ -1,28 +0,0 @@ -*CannedMessageConfig.allow_input_source max_size:16 - -*MQTTConfig.address max_size:64 -*MQTTConfig.username max_size:64 -*MQTTConfig.password max_size:64 -*MQTTConfig.root max_size:16 - -*AudioConfig.ptt_pin int_size:8 -*AudioConfig.i2s_ws int_size:8 -*AudioConfig.i2s_sd int_size:8 -*AudioConfig.i2s_din int_size:8 -*AudioConfig.i2s_sck int_size:8 - -*ExternalNotificationConfig.output_vibra int_size:8 -*ExternalNotificationConfig.output_buzzer int_size:8 -*ExternalNotificationConfig.nag_timeout int_size:16 - -*RemoteHardwareConfig.available_pins max_count:4 -*RemoteHardwarePin.name max_size:15 -*RemoteHardwarePin.gpio_pin int_size:8 - -*AmbientLightingConfig.current int_size:8 -*AmbientLightingConfig.red int_size:8 -*AmbientLightingConfig.green int_size:8 -*AmbientLightingConfig.blue int_size:8 - -*DetectionSensorConfig.monitor_pin int_size:8 -*DetectionSensorConfig.name max_size:20 \ No newline at end of file diff --git a/src/protos/meshtastic/module_config.proto b/src/protos/meshtastic/module_config.proto deleted file mode 100644 index f2c2805..0000000 --- a/src/protos/meshtastic/module_config.proto +++ /dev/null @@ -1,801 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "ModuleConfigProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * Module Config - */ -message ModuleConfig { - /* - * MQTT Client Config - */ - message MQTTConfig { - /* - * If a meshtastic node is able to reach the internet it will normally attempt to gateway any channels that are marked as - * is_uplink_enabled or is_downlink_enabled. - */ - bool enabled = 1; - - /* - * The server to use for our MQTT global message gateway feature. - * If not set, the default server will be used - */ - string address = 2; - - /* - * MQTT username to use (most useful for a custom MQTT server). - * If using a custom server, this will be honoured even if empty. - * If using the default server, this will only be honoured if set, otherwise the device will use the default username - */ - string username = 3; - - /* - * MQTT password to use (most useful for a custom MQTT server). - * If using a custom server, this will be honoured even if empty. - * If using the default server, this will only be honoured if set, otherwise the device will use the default password - */ - string password = 4; - - /* - * Whether to send encrypted or decrypted packets to MQTT. - * This parameter is only honoured if you also set server - * (the default official mqtt.meshtastic.org server can handle encrypted packets) - * Decrypted packets may be useful for external systems that want to consume meshtastic packets - */ - bool encryption_enabled = 5; - - /* - * Whether to send / consume json packets on MQTT - */ - bool json_enabled = 6; - - /* - * If true, we attempt to establish a secure connection using TLS - */ - bool tls_enabled = 7; - - /* - * The root topic to use for MQTT messages. Default is "msh". - * This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs - */ - string root = 8; - - /* - * If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection - */ - bool proxy_to_client_enabled = 9; - - /* - * If true, we will periodically report unencrypted information about our node to a map via MQTT - */ - bool map_reporting_enabled = 10; - - /* - * Settings for reporting information about our node to a map via MQTT - */ - MapReportSettings map_report_settings = 11; - } - - /* - * Settings for reporting unencrypted information about our node to a map via MQTT - */ - message MapReportSettings { - /* - * How often we should report our info to the map (in seconds) - */ - uint32 publish_interval_secs = 1; - - /* - * Bits of precision for the location sent (default of 32 is full precision). - */ - uint32 position_precision = 2; - } - - /* - * RemoteHardwareModule Config - */ - message RemoteHardwareConfig { - /* - * Whether the Module is enabled - */ - bool enabled = 1; - - /* - * Whether the Module allows consumers to read / write to pins not defined in available_pins - */ - bool allow_undefined_pin_access = 2; - - /* - * Exposes the available pins to the mesh for reading and writing - */ - repeated RemoteHardwarePin available_pins = 3; - } - - /* - * NeighborInfoModule Config - */ - message NeighborInfoConfig { - /* - * Whether the Module is enabled - */ - bool enabled = 1; - - /* - * Interval in seconds of how often we should try to send our - * Neighbor Info to the mesh - */ - uint32 update_interval = 2; - } - - /* - * Detection Sensor Module Config - */ - message DetectionSensorConfig { - /* - * Whether the Module is enabled - */ - bool enabled = 1; - - /* - * Interval in seconds of how often we can send a message to the mesh when a state change is detected - */ - uint32 minimum_broadcast_secs = 2; - - /* - * Interval in seconds of how often we should send a message to the mesh with the current state regardless of changes - * When set to 0, only state changes will be broadcasted - * Works as a sort of status heartbeat for peace of mind - */ - uint32 state_broadcast_secs = 3; - /* - * Send ASCII bell with alert message - * Useful for triggering ext. notification on bell - */ - bool send_bell = 4; - - /* - * Friendly name used to format message sent to mesh - * Example: A name "Motion" would result in a message "Motion detected" - * Maximum length of 20 characters - */ - string name = 5; - - /* - * GPIO pin to monitor for state changes - */ - uint32 monitor_pin = 6; - - /* - * Whether or not the GPIO pin state detection is triggered on HIGH (1) - * Otherwise LOW (0) - */ - bool detection_triggered_high = 7; - - /* - * Whether or not use INPUT_PULLUP mode for GPIO pin - * Only applicable if the board uses pull-up resistors on the pin - */ - bool use_pullup = 8; - } - - /* - * Audio Config for codec2 voice - */ - message AudioConfig { - /* - * Baudrate for codec2 voice - */ - enum Audio_Baud { - CODEC2_DEFAULT = 0; - CODEC2_3200 = 1; - CODEC2_2400 = 2; - CODEC2_1600 = 3; - CODEC2_1400 = 4; - CODEC2_1300 = 5; - CODEC2_1200 = 6; - CODEC2_700 = 7; - CODEC2_700B = 8; - } - - /* - * Whether Audio is enabled - */ - bool codec2_enabled = 1; - - /* - * PTT Pin - */ - uint32 ptt_pin = 2; - - /* - * The audio sample rate to use for codec2 - */ - Audio_Baud bitrate = 3; - - /* - * I2S Word Select - */ - uint32 i2s_ws = 4; - - /* - * I2S Data IN - */ - uint32 i2s_sd = 5; - - /* - * I2S Data OUT - */ - uint32 i2s_din = 6; - - /* - * I2S Clock - */ - uint32 i2s_sck = 7; - } - - /* - * Config for the Paxcounter Module - */ - message PaxcounterConfig { - /* - * Enable the Paxcounter Module - */ - bool enabled = 1; - - /* - * Interval in seconds of how often we should try to send our - * metrics to the mesh - */ - - uint32 paxcounter_update_interval = 2; - } - - /* - * Serial Config - */ - message SerialConfig { - /* - * TODO: REPLACE - */ - enum Serial_Baud { - BAUD_DEFAULT = 0; - BAUD_110 = 1; - BAUD_300 = 2; - BAUD_600 = 3; - BAUD_1200 = 4; - BAUD_2400 = 5; - BAUD_4800 = 6; - BAUD_9600 = 7; - BAUD_19200 = 8; - BAUD_38400 = 9; - BAUD_57600 = 10; - BAUD_115200 = 11; - BAUD_230400 = 12; - BAUD_460800 = 13; - BAUD_576000 = 14; - BAUD_921600 = 15; - } - - /* - * TODO: REPLACE - */ - enum Serial_Mode { - DEFAULT = 0; - SIMPLE = 1; - PROTO = 2; - TEXTMSG = 3; - NMEA = 4; - // NMEA messages specifically tailored for CalTopo - CALTOPO = 5; - } - - /* - * Preferences for the SerialModule - */ - bool enabled = 1; - - /* - * TODO: REPLACE - */ - bool echo = 2; - - /* - * RX pin (should match Arduino gpio pin number) - */ - uint32 rxd = 3; - - /* - * TX pin (should match Arduino gpio pin number) - */ - uint32 txd = 4; - - /* - * Serial baud rate - */ - Serial_Baud baud = 5; - - /* - * TODO: REPLACE - */ - uint32 timeout = 6; - - /* - * Mode for serial module operation - */ - Serial_Mode mode = 7; - - /* - * Overrides the platform's defacto Serial port instance to use with Serial module config settings - * This is currently only usable in output modes like NMEA / CalTopo and may behave strangely or not work at all in other modes - * Existing logging over the Serial Console will still be present - */ - bool override_console_serial_port = 8; - } - - /* - * External Notifications Config - */ - message ExternalNotificationConfig { - /* - * Enable the ExternalNotificationModule - */ - bool enabled = 1; - - /* - * When using in On/Off mode, keep the output on for this many - * milliseconds. Default 1000ms (1 second). - */ - uint32 output_ms = 2; - - /* - * Define the output pin GPIO setting Defaults to - * EXT_NOTIFY_OUT if set for the board. - * In standalone devices this pin should drive the LED to match the UI. - */ - uint32 output = 3; - - /* - * Optional: Define a secondary output pin for a vibra motor - * This is used in standalone devices to match the UI. - */ - uint32 output_vibra = 8; - - /* - * Optional: Define a tertiary output pin for an active buzzer - * This is used in standalone devices to to match the UI. - */ - uint32 output_buzzer = 9; - - /* - * IF this is true, the 'output' Pin will be pulled active high, false - * means active low. - */ - bool active = 4; - - /* - * True: Alert when a text message arrives (output) - */ - bool alert_message = 5; - - /* - * True: Alert when a text message arrives (output_vibra) - */ - bool alert_message_vibra = 10; - - /* - * True: Alert when a text message arrives (output_buzzer) - */ - bool alert_message_buzzer = 11; - - /* - * True: Alert when the bell character is received (output) - */ - bool alert_bell = 6; - - /* - * True: Alert when the bell character is received (output_vibra) - */ - bool alert_bell_vibra = 12; - - /* - * True: Alert when the bell character is received (output_buzzer) - */ - bool alert_bell_buzzer = 13; - - /* - * use a PWM output instead of a simple on/off output. This will ignore - * the 'output', 'output_ms' and 'active' settings and use the - * device.buzzer_gpio instead. - */ - bool use_pwm = 7; - - /* - * The notification will toggle with 'output_ms' for this time of seconds. - * Default is 0 which means don't repeat at all. 60 would mean blink - * and/or beep for 60 seconds - */ - uint32 nag_timeout = 14; - - /* - * When true, enables devices with native I2S audio output to use the RTTTL over speaker like a buzzer - * T-Watch S3 and T-Deck for example have this capability - */ - bool use_i2s_as_buzzer = 15; - } - - /* - * Store and Forward Module Config - */ - message StoreForwardConfig { - /* - * Enable the Store and Forward Module - */ - bool enabled = 1; - - /* - * TODO: REPLACE - */ - bool heartbeat = 2; - - /* - * TODO: REPLACE - */ - uint32 records = 3; - - /* - * TODO: REPLACE - */ - uint32 history_return_max = 4; - - /* - * TODO: REPLACE - */ - uint32 history_return_window = 5; - } - - /* - * Preferences for the RangeTestModule - */ - message RangeTestConfig { - /* - * Enable the Range Test Module - */ - bool enabled = 1; - - /* - * Send out range test messages from this node - */ - uint32 sender = 2; - - /* - * Bool value indicating that this node should save a RangeTest.csv file. - * ESP32 Only - */ - bool save = 3; - } - - /* - * Configuration for both device and environment metrics - */ - message TelemetryConfig { - /* - * Interval in seconds of how often we should try to send our - * device metrics to the mesh - */ - uint32 device_update_interval = 1; - - /* - * Interval in seconds of how often we should try to send our - * environment measurements to the mesh - */ - - uint32 environment_update_interval = 2; - - /* - * Preferences for the Telemetry Module (Environment) - * Enable/Disable the telemetry measurement module measurement collection - */ - bool environment_measurement_enabled = 3; - - /* - * Enable/Disable the telemetry measurement module on-device display - */ - bool environment_screen_enabled = 4; - - /* - * We'll always read the sensor in Celsius, but sometimes we might want to - * display the results in Fahrenheit as a "user preference". - */ - bool environment_display_fahrenheit = 5; - - /* - * Enable/Disable the air quality metrics - */ - bool air_quality_enabled = 6; - - /* - * Interval in seconds of how often we should try to send our - * air quality metrics to the mesh - */ - uint32 air_quality_interval = 7; - - /* - * Interval in seconds of how often we should try to send our - * air quality metrics to the mesh - */ - bool power_measurement_enabled = 8; - - /* - * Interval in seconds of how often we should try to send our - * air quality metrics to the mesh - */ - uint32 power_update_interval = 9; - - /* - * Interval in seconds of how often we should try to send our - * air quality metrics to the mesh - */ - bool power_screen_enabled = 10; - - - - - - - - - - } - - /* - * TODO: REPLACE - */ - message CannedMessageConfig { - /* - * TODO: REPLACE - */ - enum InputEventChar { - /* - * TODO: REPLACE - */ - NONE = 0; - - /* - * TODO: REPLACE - */ - UP = 17; - - /* - * TODO: REPLACE - */ - DOWN = 18; - - /* - * TODO: REPLACE - */ - LEFT = 19; - - /* - * TODO: REPLACE - */ - RIGHT = 20; - - /* - * '\n' - */ - SELECT = 10; - - /* - * TODO: REPLACE - */ - BACK = 27; - - /* - * TODO: REPLACE - */ - CANCEL = 24; - } - - /* - * Enable the rotary encoder #1. This is a 'dumb' encoder sending pulses on both A and B pins while rotating. - */ - bool rotary1_enabled = 1; - - /* - * GPIO pin for rotary encoder A port. - */ - uint32 inputbroker_pin_a = 2; - - /* - * GPIO pin for rotary encoder B port. - */ - uint32 inputbroker_pin_b = 3; - - /* - * GPIO pin for rotary encoder Press port. - */ - uint32 inputbroker_pin_press = 4; - - /* - * Generate input event on CW of this kind. - */ - InputEventChar inputbroker_event_cw = 5; - - /* - * Generate input event on CCW of this kind. - */ - InputEventChar inputbroker_event_ccw = 6; - - /* - * Generate input event on Press of this kind. - */ - InputEventChar inputbroker_event_press = 7; - - /* - * Enable the Up/Down/Select input device. Can be RAK rotary encoder or 3 buttons. Uses the a/b/press definitions from inputbroker. - */ - bool updown1_enabled = 8; - - /* - * Enable/disable CannedMessageModule. - */ - bool enabled = 9; - - /* - * Input event origin accepted by the canned message module. - * Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any" - */ - string allow_input_source = 10; - - /* - * CannedMessageModule also sends a bell character with the messages. - * ExternalNotificationModule can benefit from this feature. - */ - bool send_bell = 11; - } - - /* - Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. - Initially created for the RAK14001 RGB LED module. - */ - message AmbientLightingConfig { - - /* - * Sets LED to on or off. - */ - bool led_state = 1; - - /* - * Sets the current for the LED output. Default is 10. - */ - uint32 current = 2; - - /* - * Sets the red LED level. Values are 0-255. - */ - uint32 red = 3; - - /* - * Sets the green LED level. Values are 0-255. - */ - uint32 green = 4; - - /* - * Sets the blue LED level. Values are 0-255. - */ - uint32 blue = 5; - } - - /* - * TODO: REPLACE - */ - oneof payload_variant { - /* - * TODO: REPLACE - */ - MQTTConfig mqtt = 1; - - /* - * TODO: REPLACE - */ - SerialConfig serial = 2; - - /* - * TODO: REPLACE - */ - ExternalNotificationConfig external_notification = 3; - - /* - * TODO: REPLACE - */ - StoreForwardConfig store_forward = 4; - - /* - * TODO: REPLACE - */ - RangeTestConfig range_test = 5; - - /* - * TODO: REPLACE - */ - TelemetryConfig telemetry = 6; - - /* - * TODO: REPLACE - */ - CannedMessageConfig canned_message = 7; - - /* - * TODO: REPLACE - */ - AudioConfig audio = 8; - - /* - * TODO: REPLACE - */ - RemoteHardwareConfig remote_hardware = 9; - - /* - * TODO: REPLACE - */ - NeighborInfoConfig neighbor_info = 10; - - /* - * TODO: REPLACE - */ - AmbientLightingConfig ambient_lighting = 11; - - /* - * TODO: REPLACE - */ - DetectionSensorConfig detection_sensor = 12; - - /* - * TODO: REPLACE - */ - PaxcounterConfig paxcounter = 13; - } -} - -/* - * A GPIO pin definition for remote hardware module - */ -message RemoteHardwarePin { - /* - * GPIO Pin number (must match Arduino) - */ - uint32 gpio_pin = 1; - - /* - * Name for the GPIO pin (i.e. Front gate, mailbox, etc) - */ - string name = 2; - - /* - * Type of GPIO access available to consumers on the mesh - */ - RemoteHardwarePinType type = 3; -} - -enum RemoteHardwarePinType { - /* - * Unset/unused - */ - UNKNOWN = 0; - - /* - * GPIO pin can be read (if it is high / low) - */ - DIGITAL_READ = 1; - - /* - * GPIO pin can be written to (high / low) - */ - DIGITAL_WRITE = 2; -} \ No newline at end of file diff --git a/src/protos/meshtastic/mqtt.options b/src/protos/meshtastic/mqtt.options deleted file mode 100644 index 591e898..0000000 --- a/src/protos/meshtastic/mqtt.options +++ /dev/null @@ -1,8 +0,0 @@ -*ServiceEnvelope.packet type:FT_POINTER -*ServiceEnvelope.channel_id type:FT_POINTER -*ServiceEnvelope.gateway_id type:FT_POINTER - -*MapReport.long_name max_size:40 -*MapReport.short_name max_size:5 -*MapReport.firmware_version max_size:18 -*MapReport.num_online_local_nodes int_size:16 \ No newline at end of file diff --git a/src/protos/meshtastic/mqtt.proto b/src/protos/meshtastic/mqtt.proto deleted file mode 100644 index 17ebf0e..0000000 --- a/src/protos/meshtastic/mqtt.proto +++ /dev/null @@ -1,106 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -import "meshtastic/mesh.proto"; -import "meshtastic/config.proto"; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "MQTTProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * This message wraps a MeshPacket with extra metadata about the sender and how it arrived. - */ -message ServiceEnvelope { - /* - * The (probably encrypted) packet - */ - MeshPacket packet = 1; - - /* - * The global channel ID it was sent on - */ - string channel_id = 2; - - /* - * The sending gateway node ID. Can we use this to authenticate/prevent fake - * nodeid impersonation for senders? - i.e. use gateway/mesh id (which is authenticated) + local node id as - * the globally trusted nodenum - */ - string gateway_id = 3; -} - -/* - * Information about a node intended to be reported unencrypted to a map using MQTT. - */ -message MapReport { - /* - * A full name for this user, i.e. "Kevin Hester" - */ - string long_name = 1; - - /* - * A VERY short name, ideally two characters. - * Suitable for a tiny OLED screen - */ - string short_name = 2; - - /* - * Role of the node that applies specific settings for a particular use-case - */ - Config.DeviceConfig.Role role = 3; - - /* - * Hardware model of the node, i.e. T-Beam, Heltec V3, etc... - */ - HardwareModel hw_model = 4; - - /* - * Device firmware version string - */ - string firmware_version = 5; - - /* - * The region code for the radio (US, CN, EU433, etc...) - */ - Config.LoRaConfig.RegionCode region = 6; - - /* - * Modem preset used by the radio (LongFast, MediumSlow, etc...) - */ - Config.LoRaConfig.ModemPreset modem_preset = 7; - - /* - * Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...) - * and it uses the default frequency slot given the region and modem preset. - */ - bool has_default_channel = 8; - - /* - * Latitude: multiply by 1e-7 to get degrees in floating point - */ - sfixed32 latitude_i = 9; - - /* - * Longitude: multiply by 1e-7 to get degrees in floating point - */ - sfixed32 longitude_i = 10; - - /* - * Altitude in meters above MSL - */ - int32 altitude = 11; - - /* - * Indicates the bits of precision for latitude and longitude set by the sending node - */ - uint32 position_precision = 12; - - /* - * Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT) - */ - uint32 num_online_local_nodes = 13; -} \ No newline at end of file diff --git a/src/protos/meshtastic/paxcount.proto b/src/protos/meshtastic/paxcount.proto deleted file mode 100644 index 47b2639..0000000 --- a/src/protos/meshtastic/paxcount.proto +++ /dev/null @@ -1,29 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "PaxcountProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * TODO: REPLACE - */ -message Paxcount { - /* - * seen Wifi devices - */ - uint32 wifi = 1; - - /* - * Seen BLE devices - */ - uint32 ble = 2; - - /* - * Uptime in seconds - */ - uint32 uptime = 3; -} diff --git a/src/protos/meshtastic/portnums.proto b/src/protos/meshtastic/portnums.proto deleted file mode 100644 index b02651a..0000000 --- a/src/protos/meshtastic/portnums.proto +++ /dev/null @@ -1,216 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "Portnums"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a - * unique 'portnum' for their application. - * If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to this - * master table. - * PortNums should be assigned in the following range: - * 0-63 Core Meshtastic use, do not use for third party apps - * 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application - * 256-511 Use one of these portnums for your private applications that you don't want to register publically - * All other values are reserved. - * Note: This was formerly a Type enum named 'typ' with the same id # - * We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. - * This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically. - */ -enum PortNum { - /* - * Deprecated: do not use in new code (formerly called OPAQUE) - * A message sent from a device outside of the mesh, in a form the mesh does not understand - * NOTE: This must be 0, because it is documented in IMeshService.aidl to be so - * ENCODING: binary undefined - */ - UNKNOWN_APP = 0; - - /* - * A simple UTF-8 text message, which even the little micros in the mesh - * can understand and show on their screen eventually in some circumstances - * even signal might send messages in this form (see below) - * ENCODING: UTF-8 Plaintext (?) - */ - TEXT_MESSAGE_APP = 1; - - /* - * Reserved for built-in GPIO/example app. - * See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number - * ENCODING: Protobuf - */ - REMOTE_HARDWARE_APP = 2; - - /* - * The built-in position messaging app. - * Payload is a Position message. - * ENCODING: Protobuf - */ - POSITION_APP = 3; - - /* - * The built-in user info app. - * Payload is a User message. - * ENCODING: Protobuf - */ - NODEINFO_APP = 4; - - /* - * Protocol control packets for mesh protocol use. - * Payload is a Routing message. - * ENCODING: Protobuf - */ - ROUTING_APP = 5; - - /* - * Admin control packets. - * Payload is a AdminMessage message. - * ENCODING: Protobuf - */ - ADMIN_APP = 6; - - /* - * Compressed TEXT_MESSAGE payloads. - * ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression - * NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed - * payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress - * any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. - */ - TEXT_MESSAGE_COMPRESSED_APP = 7; - - /* - * Waypoint payloads. - * Payload is a Waypoint message. - * ENCODING: Protobuf - */ - WAYPOINT_APP = 8; - - /* - * Audio Payloads. - * Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now - * ENCODING: codec2 audio frames - * NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate. - * This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. - */ - AUDIO_APP = 9; - - /* - * Same as Text Message but originating from Detection Sensor Module. - * NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 - */ - DETECTION_SENSOR_APP = 10; - - /* - * Provides a 'ping' service that replies to any packet it receives. - * Also serves as a small example module. - * ENCODING: ASCII Plaintext - */ - REPLY_APP = 32; - - /* - * Used for the python IP tunnel feature - * ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. - */ - IP_TUNNEL_APP = 33; - - /* - * Paxcounter lib included in the firmware - * ENCODING: protobuf - */ - PAXCOUNTER_APP = 34; - - /* - * Provides a hardware serial interface to send and receive from the Meshtastic network. - * Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic - * network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network. - * Maximum packet size of 240 bytes. - * Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp. - * ENCODING: binary undefined - */ - SERIAL_APP = 64; - - /* - * STORE_FORWARD_APP (Work in Progress) - * Maintained by Jm Casler (MC Hamster) : jm@casler.org - * ENCODING: Protobuf - */ - STORE_FORWARD_APP = 65; - - /* - * Optional port for messages for the range test module. - * ENCODING: ASCII Plaintext - * NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 - */ - RANGE_TEST_APP = 66; - - /* - * Provides a format to send and receive telemetry data from the Meshtastic network. - * Maintained by Charles Crossan (crossan007) : crossan007@gmail.com - * ENCODING: Protobuf - */ - TELEMETRY_APP = 67; - - /* - * Experimental tools for estimating node position without a GPS - * Maintained by Github user a-f-G-U-C (a Meshtastic contributor) - * Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS - * ENCODING: arrays of int64 fields - */ - ZPS_APP = 68; - - /* - * Used to let multiple instances of Linux native applications communicate - * as if they did using their LoRa chip. - * Maintained by GitHub user GUVWAF. - * Project files at https://github.com/GUVWAF/Meshtasticator - * ENCODING: Protobuf (?) - */ - SIMULATOR_APP = 69; - - /* - * Provides a traceroute functionality to show the route a packet towards - * a certain destination would take on the mesh. - * ENCODING: Protobuf - */ - TRACEROUTE_APP = 70; - - /* - * Aggregates edge info for the network by sending out a list of each node's neighbors - * ENCODING: Protobuf - */ - NEIGHBORINFO_APP = 71; - - /* - * ATAK Plugin - * Portnum for payloads from the official Meshtastic ATAK plugin - */ - ATAK_PLUGIN = 72; - - /* - * Provides unencrypted information about a node for consumption by a map via MQTT - */ - MAP_REPORT_APP = 73; - - /* - * Private applications should use portnums >= 256. - * To simplify initial development and testing you can use "PRIVATE_APP" - * in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) - */ - PRIVATE_APP = 256; - - /* - * ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder - * ENCODING: libcotshrink - */ - ATAK_FORWARDER = 257; - - /* - * Currently we limit port nums to no higher than this value - */ - MAX = 511; -} \ No newline at end of file diff --git a/src/protos/meshtastic/remote_hardware.proto b/src/protos/meshtastic/remote_hardware.proto deleted file mode 100644 index ba4a693..0000000 --- a/src/protos/meshtastic/remote_hardware.proto +++ /dev/null @@ -1,75 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "RemoteHardware"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * An example app to show off the module system. This message is used for - * REMOTE_HARDWARE_APP PortNums. - * Also provides easy remote access to any GPIO. - * In the future other remote hardware operations can be added based on user interest - * (i.e. serial output, spi/i2c input/output). - * FIXME - currently this feature is turned on by default which is dangerous - * because no security yet (beyond the channel mechanism). - * It should be off by default and then protected based on some TBD mechanism - * (a special channel once multichannel support is included?) - */ -message HardwareMessage { - /* - * TODO: REPLACE - */ - enum Type { - /* - * Unset/unused - */ - UNSET = 0; - - /* - * Set gpio gpios based on gpio_mask/gpio_value - */ - WRITE_GPIOS = 1; - - /* - * We are now interested in watching the gpio_mask gpios. - * If the selected gpios change, please broadcast GPIOS_CHANGED. - * Will implicitly change the gpios requested to be INPUT gpios. - */ - WATCH_GPIOS = 2; - - /* - * The gpios listed in gpio_mask have changed, the new values are listed in gpio_value - */ - GPIOS_CHANGED = 3; - - /* - * Read the gpios specified in gpio_mask, send back a READ_GPIOS_REPLY reply with gpio_value populated - */ - READ_GPIOS = 4; - - /* - * A reply to READ_GPIOS. gpio_mask and gpio_value will be populated - */ - READ_GPIOS_REPLY = 5; - } - - /* - * What type of HardwareMessage is this? - */ - Type type = 1; - - /* - * What gpios are we changing. Not used for all MessageTypes, see MessageType for details - */ - uint64 gpio_mask = 2; - - /* - * For gpios that were listed in gpio_mask as valid, what are the signal levels for those gpios. - * Not used for all MessageTypes, see MessageType for details - */ - uint64 gpio_value = 3; -} diff --git a/src/protos/meshtastic/rtttl.options b/src/protos/meshtastic/rtttl.options deleted file mode 100644 index 1ae0c2f..0000000 --- a/src/protos/meshtastic/rtttl.options +++ /dev/null @@ -1 +0,0 @@ -*RTTTLConfig.ringtone max_size:230 diff --git a/src/protos/meshtastic/rtttl.proto b/src/protos/meshtastic/rtttl.proto deleted file mode 100644 index 11c8b92..0000000 --- a/src/protos/meshtastic/rtttl.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "RTTTLConfigProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * Canned message module configuration. - */ -message RTTTLConfig { - /* - * Ringtone for PWM Buzzer in RTTTL Format. - */ - string ringtone = 1; -} diff --git a/src/protos/meshtastic/storeforward.options b/src/protos/meshtastic/storeforward.options deleted file mode 100644 index 8580aab..0000000 --- a/src/protos/meshtastic/storeforward.options +++ /dev/null @@ -1 +0,0 @@ -*StoreAndForward.text max_size:237 \ No newline at end of file diff --git a/src/protos/meshtastic/storeforward.proto b/src/protos/meshtastic/storeforward.proto deleted file mode 100644 index ef7de2c..0000000 --- a/src/protos/meshtastic/storeforward.proto +++ /dev/null @@ -1,218 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "StoreAndForwardProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * TODO: REPLACE - */ -message StoreAndForward { - /* - * 001 - 063 = From Router - * 064 - 127 = From Client - */ - enum RequestResponse { - /* - * Unset/unused - */ - UNSET = 0; - - /* - * Router is an in error state. - */ - ROUTER_ERROR = 1; - - /* - * Router heartbeat - */ - ROUTER_HEARTBEAT = 2; - - /* - * Router has requested the client respond. This can work as a - * "are you there" message. - */ - ROUTER_PING = 3; - - /* - * The response to a "Ping" - */ - ROUTER_PONG = 4; - - /* - * Router is currently busy. Please try again later. - */ - ROUTER_BUSY = 5; - - /* - * Router is responding to a request for history. - */ - ROUTER_HISTORY = 6; - - /* - * Router is responding to a request for stats. - */ - ROUTER_STATS = 7; - - /* - * Router sends a text message from its history that was a direct message. - */ - ROUTER_TEXT_DIRECT = 8; - - /* - * Router sends a text message from its history that was a broadcast. - */ - ROUTER_TEXT_BROADCAST = 9; - - /* - * Client is an in error state. - */ - CLIENT_ERROR = 64; - - /* - * Client has requested a replay from the router. - */ - CLIENT_HISTORY = 65; - - /* - * Client has requested stats from the router. - */ - CLIENT_STATS = 66; - - /* - * Client has requested the router respond. This can work as a - * "are you there" message. - */ - CLIENT_PING = 67; - - /* - * The response to a "Ping" - */ - CLIENT_PONG = 68; - - /* - * Client has requested that the router abort processing the client's request - */ - CLIENT_ABORT = 106; - } - - /* - * TODO: REPLACE - */ - message Statistics { - /* - * Number of messages we have ever seen - */ - uint32 messages_total = 1; - - /* - * Number of messages we have currently saved our history. - */ - uint32 messages_saved = 2; - - /* - * Maximum number of messages we will save - */ - uint32 messages_max = 3; - - /* - * Router uptime in seconds - */ - uint32 up_time = 4; - - /* - * Number of times any client sent a request to the S&F. - */ - uint32 requests = 5; - - /* - * Number of times the history was requested. - */ - uint32 requests_history = 6; - - /* - * Is the heartbeat enabled on the server? - */ - bool heartbeat = 7; - - /* - * Maximum number of messages the server will return. - */ - uint32 return_max = 8; - - /* - * Maximum history window in minutes the server will return messages from. - */ - uint32 return_window = 9; - } - - /* - * TODO: REPLACE - */ - message History { - /* - * Number of that will be sent to the client - */ - uint32 history_messages = 1; - - /* - * The window of messages that was used to filter the history client requested - */ - uint32 window = 2; - - /* - * Index in the packet history of the last message sent in a previous request to the server. - * Will be sent to the client before sending the history and can be set in a subsequent request to avoid getting packets the server already sent to the client. - */ - uint32 last_request = 3; - } - - /* - * TODO: REPLACE - */ - message Heartbeat { - /* - * Period in seconds that the heartbeat is sent out that will be sent to the client - */ - uint32 period = 1; - - /* - * If set, this is not the primary Store & Forward router on the mesh - */ - uint32 secondary = 2; - } - - /* - * TODO: REPLACE - */ - RequestResponse rr = 1; - - /* - * TODO: REPLACE - */ - oneof variant { - /* - * TODO: REPLACE - */ - Statistics stats = 2; - - /* - * TODO: REPLACE - */ - History history = 3; - - /* - * TODO: REPLACE - */ - Heartbeat heartbeat = 4; - - /* - * Text from history message. - */ - bytes text = 5; - } -} \ No newline at end of file diff --git a/src/protos/meshtastic/telemetry.options b/src/protos/meshtastic/telemetry.options deleted file mode 100644 index 2fe657c..0000000 --- a/src/protos/meshtastic/telemetry.options +++ /dev/null @@ -1,4 +0,0 @@ -# options for nanopb -# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options - -*EnvironmentMetrics.iaq int_size:16 \ No newline at end of file diff --git a/src/protos/meshtastic/telemetry.proto b/src/protos/meshtastic/telemetry.proto deleted file mode 100644 index 78c0e4f..0000000 --- a/src/protos/meshtastic/telemetry.proto +++ /dev/null @@ -1,560 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "TelemetryProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -/* - * Key native device metrics such as battery level - */ -message DeviceMetrics { - /* - * 0-100 (>100 means powered) - */ - optional uint32 battery_level = 1; - - /* - * Voltage measured - */ - optional float voltage = 2; - - /* - * Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). - */ - optional float channel_utilization = 3; - - /* - * Percent of airtime for transmission used within the last hour. - */ - optional float air_util_tx = 4; - - /* - * How long the device has been running since the last reboot (in seconds) - */ - optional uint32 uptime_seconds = 5; -} - -/* - * Weather station or other environmental metrics - */ -message EnvironmentMetrics { - /* - * Temperature measured - */ - optional float temperature = 1; - - /* - * Relative humidity percent measured - */ - optional float relative_humidity = 2; - - /* - * Barometric pressure in hPA measured - */ - optional float barometric_pressure = 3; - - /* - * Gas resistance in MOhm measured - */ - optional float gas_resistance = 4; - - /* - * Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) - */ - optional float voltage = 5; - - /* - * Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) - */ - optional float current = 6; - - /* - * relative scale IAQ value as measured by Bosch BME680 . value 0-500. - * Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. - */ - optional uint32 iaq = 7; - - /* - * RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. - */ - optional float distance = 8; - - /* - * VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. - */ - optional float lux = 9; - - /* - * VEML7700 high accuracy white light(irradiance) not calibrated digital 16-bit resolution sensor. - */ - optional float white_lux = 10; - - /* - * Infrared lux - */ - optional float ir_lux = 11; - - /* - * Ultraviolet lux - */ - optional float uv_lux = 12; - - /* - * Wind direction in degrees - * 0 degrees = North, 90 = East, etc... - */ - optional uint32 wind_direction = 13; - - /* - * Wind speed in m/s - */ - optional float wind_speed = 14; - - /* - * Weight in KG - */ - optional float weight = 15; - - /* - * Wind gust in m/s - */ - optional float wind_gust = 16; - - /* - * Wind lull in m/s - */ - optional float wind_lull = 17; - - /* - * Radiation in µR/h - */ - optional float radiation = 18; - -} - -/* - * Power Metrics (voltage / current / etc) - */ -message PowerMetrics { - /* - * Voltage (Ch1) - */ - optional float ch1_voltage = 1; - - /* - * Current (Ch1) - */ - optional float ch1_current = 2; - - /* - * Voltage (Ch2) - */ - optional float ch2_voltage = 3; - - /* - * Current (Ch2) - */ - optional float ch2_current = 4; - - /* - * Voltage (Ch3) - */ - optional float ch3_voltage = 5; - - /* - * Current (Ch3) - */ - optional float ch3_current = 6; -} - -/* - * Air quality metrics - */ -message AirQualityMetrics { - /* - * Concentration Units Standard PM1.0 - */ - optional uint32 pm10_standard = 1; - - /* - * Concentration Units Standard PM2.5 - */ - optional uint32 pm25_standard = 2; - - /* - * Concentration Units Standard PM10.0 - */ - optional uint32 pm100_standard = 3; - - /* - * Concentration Units Environmental PM1.0 - */ - optional uint32 pm10_environmental = 4; - - /* - * Concentration Units Environmental PM2.5 - */ - optional uint32 pm25_environmental = 5; - - /* - * Concentration Units Environmental PM10.0 - */ - optional uint32 pm100_environmental = 6; - - /* - * 0.3um Particle Count - */ - optional uint32 particles_03um = 7; - - /* - * 0.5um Particle Count - */ - optional uint32 particles_05um = 8; - - /* - * 1.0um Particle Count - */ - optional uint32 particles_10um = 9; - - /* - * 2.5um Particle Count - */ - optional uint32 particles_25um = 10; - - /* - * 5.0um Particle Count - */ - optional uint32 particles_50um = 11; - - /* - * 10.0um Particle Count - */ - optional uint32 particles_100um = 12; - - /* - * 10.0um Particle Count - */ - optional uint32 co2 = 13; -} - -/* - * Local device mesh statistics - */ -message LocalStats { - /* - * How long the device has been running since the last reboot (in seconds) - */ - uint32 uptime_seconds = 1; - /* - * Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). - */ - float channel_utilization = 2; - /* - * Percent of airtime for transmission used within the last hour. - */ - float air_util_tx = 3; - - /* - * Number of packets sent - */ - uint32 num_packets_tx = 4; - - /* - * Number of packets received (both good and bad) - */ - uint32 num_packets_rx = 5; - - /* - * Number of packets received that are malformed or violate the protocol - */ - uint32 num_packets_rx_bad = 6; - - /* - * Number of nodes online (in the past 2 hours) - */ - uint32 num_online_nodes = 7; - - /* - * Number of nodes total - */ - uint32 num_total_nodes = 8; - - /* - * Number of received packets that were duplicates (due to multiple nodes relaying). - * If this number is high, there are nodes in the mesh relaying packets when it's unnecessary, for example due to the ROUTER/REPEATER role. - */ - uint32 num_rx_dupe = 9; - - /* - * Number of packets we transmitted that were a relay for others (not originating from ourselves). - */ - uint32 num_tx_relay = 10; - - /* - * Number of times we canceled a packet to be relayed, because someone else did it before us. - * This will always be zero for ROUTERs/REPEATERs. If this number is high, some other node(s) is/are relaying faster than you. - */ - uint32 num_tx_relay_canceled = 11; -} - -/* - * Health telemetry metrics - */ -message HealthMetrics { - /* - * Heart rate (beats per minute) - */ - optional uint32 heart_bpm = 1; - - /* - * SpO2 (blood oxygen saturation) level - */ - optional uint32 spO2 = 2; - - /* - * Body temperature in degrees Celsius - */ - optional float temperature = 3; -} - -/* - * Types of Measurements the telemetry module is equipped to handle - */ -message Telemetry { - /* - * Seconds since 1970 - or 0 for unknown/unset - */ - fixed32 time = 1; - - oneof variant { - /* - * Key native device metrics such as battery level - */ - DeviceMetrics device_metrics = 2; - - /* - * Weather station or other environmental metrics - */ - EnvironmentMetrics environment_metrics = 3; - - /* - * Air quality metrics - */ - AirQualityMetrics air_quality_metrics = 4; - - /* - * Power Metrics - */ - PowerMetrics power_metrics = 5; - - /* - * Local device mesh statistics - */ - LocalStats local_stats = 6; - - /* - * Health telemetry metrics - */ - HealthMetrics health_metrics = 7; - } -} - -/* - * Supported I2C Sensors for telemetry in Meshtastic - */ -enum TelemetrySensorType { - /* - * No external telemetry sensor explicitly set - */ - SENSOR_UNSET = 0; - - /* - * High accuracy temperature, pressure, humidity - */ - BME280 = 1; - - /* - * High accuracy temperature, pressure, humidity, and air resistance - */ - BME680 = 2; - - /* - * Very high accuracy temperature - */ - MCP9808 = 3; - - /* - * Moderate accuracy current and voltage - */ - INA260 = 4; - - /* - * Moderate accuracy current and voltage - */ - INA219 = 5; - - /* - * High accuracy temperature and pressure - */ - BMP280 = 6; - - /* - * High accuracy temperature and humidity - */ - SHTC3 = 7; - - /* - * High accuracy pressure - */ - LPS22 = 8; - - /* - * 3-Axis magnetic sensor - */ - QMC6310 = 9; - - /* - * 6-Axis inertial measurement sensor - */ - QMI8658 = 10; - - /* - * 3-Axis magnetic sensor - */ - QMC5883L = 11; - - /* - * High accuracy temperature and humidity - */ - SHT31 = 12; - - /* - * PM2.5 air quality sensor - */ - PMSA003I = 13; - - /* - * INA3221 3 Channel Voltage / Current Sensor - */ - INA3221 = 14; - - /* - * BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280) - */ - BMP085 = 15; - - /* - * RCWL-9620 Doppler Radar Distance Sensor, used for water level detection - */ - RCWL9620 = 16; - - /* - * Sensirion High accuracy temperature and humidity - */ - SHT4X = 17; - - /* - * VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. - */ - VEML7700 = 18; - - /* - * MLX90632 non-contact IR temperature sensor. - */ - MLX90632 = 19; - - /* - * TI OPT3001 Ambient Light Sensor - */ - OPT3001 = 20; - - /* - * Lite On LTR-390UV-01 UV Light Sensor - */ - LTR390UV = 21; - - /* - * AMS TSL25911FN RGB Light Sensor - */ - TSL25911FN = 22; - - /* - * AHT10 Integrated temperature and humidity sensor - */ - AHT10 = 23; - - /* - * DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) - */ - DFROBOT_LARK = 24; - - /* - * NAU7802 Scale Chip or compatible - */ - NAU7802 = 25; - - /* - * BMP3XX High accuracy temperature and pressure - */ - BMP3XX = 26; - - /* - * ICM-20948 9-Axis digital motion processor - */ - ICM20948 = 27; - - /* - * MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) - */ - MAX17048 = 28; - - /* - * Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor - */ - CUSTOM_SENSOR = 29; - - /* - * MAX30102 Pulse Oximeter and Heart-Rate Sensor - */ - MAX30102 = 30; - - /* - * MLX90614 non-contact IR temperature sensor - */ - MLX90614 = 31; - - /* - * SCD40/SCD41 CO2, humidity, temperature sensor - */ - SCD4X = 32; - - /* - * ClimateGuard RadSens, radiation, Geiger-Muller Tube - */ - RADSENS = 33; - - /* - * High accuracy current and voltage - */ - INA226 = 34; - -} - -/* - * NAU7802 Telemetry configuration, for saving to flash - */ -message Nau7802Config { - /* - * The offset setting for the NAU7802 - */ - int32 zeroOffset = 1; - - /* - * The calibration factor for the NAU7802 - */ - float calibrationFactor = 2; -} \ No newline at end of file diff --git a/src/protos/meshtastic/xmodem.options b/src/protos/meshtastic/xmodem.options deleted file mode 100644 index 3af6125..0000000 --- a/src/protos/meshtastic/xmodem.options +++ /dev/null @@ -1,6 +0,0 @@ -# options for nanopb -# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options - -*XModem.buffer max_size:128 -*XModem.seq int_size:16 -*XModem.crc16 int_size:16 diff --git a/src/protos/meshtastic/xmodem.proto b/src/protos/meshtastic/xmodem.proto deleted file mode 100644 index 732780a..0000000 --- a/src/protos/meshtastic/xmodem.proto +++ /dev/null @@ -1,27 +0,0 @@ -syntax = "proto3"; - -package meshtastic; - -option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; -option java_outer_classname = "XmodemProtos"; -option java_package = "com.geeksville.mesh"; -option swift_prefix = ""; - -message XModem { - enum Control { - NUL = 0; - SOH = 1; - STX = 2; - EOT = 4; - ACK = 6; - NAK = 21; - CAN = 24; - CTRLZ = 26; - } - - Control control = 1; - uint32 seq = 2; - uint32 crc16 = 3; - bytes buffer = 4; -} diff --git a/src/public/assets/css/styles.css b/src/public/assets/css/styles.css new file mode 100644 index 0000000..8811cad --- /dev/null +++ b/src/public/assets/css/styles.css @@ -0,0 +1,115 @@ +/* used to prevent ui flicker before vuejs loads */ +[v-cloak] { + display: none; +} + +.icon-longfast { + background-color: #009016; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-mediumfast { + background-color: #326be7; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-shortslow { + background-color: #0077e6; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-mqtt-connected { + background-color: #2563eb; /* Change to use same color as disconnected // #16a34a; */ + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-mqtt-disconnected { + background-color: #2563eb; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-offline { + background-color: #e2286c; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-position-history { + background-color: #a855f7; + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-traceroute-start { + background-color: #16a34a; /* green */ + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.icon-traceroute-end { + background-color: #dc2626; /* red */ + border-radius: 25px; + border: 1px solid #2C2D3C; +} + +.waypoint-label { + font-size: 26px; + background-color: transparent; +} + +.link { + color: #2563eb; +} + +.link:hover { + text-decoration: underline; +} + +.tooltip { + position: relative; + display: inline-block; +} + +.tooltip .tooltip-text { + visibility: hidden; + width: 80px; + background-color: black; + color: #fff; + text-align: center; + padding: 4px 0; + border-radius: 6px; + position: absolute; + z-index: 10000; + top: 100%; + left: 50%; + margin-top: 8px; + margin-left: -40px; /* Use half of the width (120/2 = 60), to center the tooltip */ +} + +.tooltip .tooltip-text::after { + content: " "; + position: absolute; + bottom: 100%; /* At the top of the tooltip */ + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent black transparent; +} + +.tooltip:hover .tooltip-text { + visibility: visible; +} + +.z-search { + z-index: 1001; +} + +.z-sidebar { + z-index: 1002; +} \ No newline at end of file diff --git a/src/public/assets/js/app.js b/src/public/assets/js/app.js new file mode 100644 index 0000000..86b4542 --- /dev/null +++ b/src/public/assets/js/app.js @@ -0,0 +1,956 @@ +Vue.createApp({ + data() { + return { + + isShowingAnnouncement: this.shouldShowAnnouncement(), + + configNodesMaxAgeInSeconds: window.getConfigNodesMaxAgeInSeconds(), + configNodesOfflineAgeInSeconds: window.getConfigNodesOfflineAgeInSeconds(), + configWaypointsMaxAgeInSeconds: window.getConfigWaypointsMaxAgeInSeconds(), + configConnectionsMaxDistanceInMeters: window.getConfigConnectionsMaxDistanceInMeters(), + configZoomLevelGoToNode: window.getConfigZoomLevelGoToNode(), + configAutoUpdatePositionInUrl: window.getConfigAutoUpdatePositionInUrl(), + configEnableMapAnimations: window.getConfigEnableMapAnimations(), + configTemperatureFormat: window.getConfigTemperatureFormat(), + configConnectionsTimePeriodInSeconds: window.getConfigConnectionsTimePeriodInSeconds(), + configConnectionsColoredLines: window.getConfigConnectionsColoredLines(), + configConnectionsBidirectionalOnly: window.getConfigConnectionsBidirectionalOnly(), + configConnectionsMinSnrDb: window.getConfigConnectionsMinSnrDb(), + configConnectionsBidirectionalMinSnr: window.getConfigConnectionsBidirectionalMinSnr(), + + isShowingHardwareModels: false, + hardwareModelStats: null, + + isShowingInfoModal: this.shouldShowInfoModal(), + isShowingMobileSearch: false, + isShowingSettings: false, + + nodes: [], + searchText: "", + + selectedNode: null, + selectedNodeDeviceMetrics: [], + selectedNodeEnvironmentMetrics: [], + selectedNodePowerMetrics: [], + selectedNodeMqttMetrics: [], + selectedNodeTraceroutes: [], + + deviceMetricsTimeRange: "7d", + environmentMetricsTimeRange: "7d", + powerMetricsTimeRange: "7d", + + isPositionHistoryModalExpanded: true, + positionHistoryDateTimeFrom: null, + positionHistoryDateTimeTo: null, + selectedNodePositionHistory: [], + selectedNodeToShowPositionHistory: null, + selectedNodePositionHistoryMarkers: [], + selectedNodePositionHistoryPolyLines: [], + + selectedTraceRoute: null, + tracerouteEdges: [], + + selectedNodeToShowConnections: null, + + moment: window.moment, + + }; + }, + mounted: function() { + + // load data + this.loadHardwareModelStats(); + + // handle map click callback from outside of vue + window._onMapClick = () => { + this.searchText = ""; + this.isShowingMobileSearch = false; + }; + + // handle node callback from outside of vue + window._onNodeClick = (node) => { + this.selectedNode = node; + this.loadNodeDeviceMetrics(node.node_id); + this.loadNodeEnvironmentMetrics(node.node_id); + this.loadNodePowerMetrics(node.node_id); + this.loadNodeMqttMetrics(node.node_id); + this.loadNodeTraceroutes(node.node_id); + //this.loadNodePositionHistory(node.node_id); + }; + + // handle node callback from outside of vue + window._onShowNodeConnectionsClick = (node) => { + this.selectedNodeToShowConnections = node; + }; + + // handle nodes updated callback from outside of vue + window._onNodesUpdated = (nodes) => { + this.nodes = nodes; + }; + + }, + methods: { + getAnnouncementId: function() { + // change this when making a new announcement + return "1"; + }, + shouldShowAnnouncement: function() { + const lastSeenAnnouncementId = window.localStorage.getItem("last-seen-announcement-id"); + return lastSeenAnnouncementId?.toString() !== this.getAnnouncementId(); + }, + dismissAnnouncement: function() { + window.localStorage.setItem("last-seen-announcement-id", this.getAnnouncementId()); + this.isShowingAnnouncement = false; + }, + shouldShowInfoModal: function() { + return !window.getConfigHasSeenInfoModal() + && !window.isMobile(); + }, + loadHardwareModelStats: function() { + window.axios.get('/api/v1/stats/hardware-models').then((response) => { + this.hardwareModelStats = response.data.hardware_model_stats; + }).catch((error) => { + // do nothing + }); + }, + loadNodeDeviceMetrics: function(nodeId) { + + // calculate unix timestamps in milliseconds for supported time ranges + const oneDayAgoInMilliseconds = new Date().getTime() - (86400 * 1000); + const threeDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000); + const sevenDaysAgoInMilliseconds = new Date().getTime() - (604800 * 1000); + const thirtyDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000 * 10); + + // determine how long back to load device metrics from + var timeFrom = threeDaysAgoInMilliseconds; + switch(this.deviceMetricsTimeRange){ + case "1d": { + timeFrom = oneDayAgoInMilliseconds; + break; + } + case "3d": { + timeFrom = threeDaysAgoInMilliseconds; + break; + } + case "7d": { + timeFrom = sevenDaysAgoInMilliseconds; + break; + } + case "30d": { + timeFrom = thirtyDaysAgoInMilliseconds; + break; + } + } + + window.axios.get(`/api/v1/nodes/${nodeId}/device-metrics`, { + params: { + time_from: timeFrom, + }, + }).then((response) => { + // reverse response, as it's newest to oldest, but we want oldest to newest + this.selectedNodeDeviceMetrics = response.data.device_metrics.reverse(); + this.renderDeviceMetricCharts(); + }).catch(() => { + this.selectedNodeDeviceMetrics = []; + this.renderDeviceMetricCharts(); + }); + }, + loadNodeEnvironmentMetrics: function(nodeId) { + + // calculate unix timestamps in milliseconds for supported time ranges + const oneDayAgoInMilliseconds = new Date().getTime() - (86400 * 1000); + const threeDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000); + const sevenDaysAgoInMilliseconds = new Date().getTime() - (604800 * 1000); + const thirtyDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000 * 10); + + // determine how long back to load environment metrics from + var timeFrom = threeDaysAgoInMilliseconds; + switch(this.environmentMetricsTimeRange){ + case "1d": { + timeFrom = oneDayAgoInMilliseconds; + break; + } + case "3d": { + timeFrom = threeDaysAgoInMilliseconds; + break; + } + case "7d": { + timeFrom = sevenDaysAgoInMilliseconds; + break; + } + case "30d": { + timeFrom = thirtyDaysAgoInMilliseconds; + break; + } + } + + window.axios.get(`/api/v1/nodes/${nodeId}/environment-metrics`, { + params: { + time_from: timeFrom, + }, + }).then((response) => { + // reverse response, as it's newest to oldest, but we want oldest to newest + this.selectedNodeEnvironmentMetrics = response.data.environment_metrics.reverse(); + this.renderEnvironmentMetricCharts(); + }).catch(() => { + this.selectedNodeEnvironmentMetrics = []; + this.renderEnvironmentMetricCharts(); + }); + }, + loadNodePowerMetrics: function(nodeId) { + + // calculate unix timestamps in milliseconds for supported time ranges + const oneDayAgoInMilliseconds = new Date().getTime() - (86400 * 1000); + const threeDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000); + const sevenDaysAgoInMilliseconds = new Date().getTime() - (604800 * 1000); + const thirtyDaysAgoInMilliseconds = new Date().getTime() - (259200 * 1000 * 10); + + // determine how long back to load power metrics from + var timeFrom = threeDaysAgoInMilliseconds; + switch(this.powerMetricsTimeRange){ + case "1d": { + timeFrom = oneDayAgoInMilliseconds; + break; + } + case "3d": { + timeFrom = threeDaysAgoInMilliseconds; + break; + } + case "7d": { + timeFrom = sevenDaysAgoInMilliseconds; + break; + } + case "30d": { + timeFrom = thirtyDaysAgoInMilliseconds; + break; + } + } + + window.axios.get(`/api/v1/nodes/${nodeId}/power-metrics`, { + params: { + time_from: timeFrom, + }, + }).then((response) => { + // reverse response, as it's newest to oldest, but we want oldest to newest + this.selectedNodePowerMetrics = response.data.power_metrics.reverse(); + this.renderPowerMetricCharts(); + }).catch(() => { + this.selectedNodePowerMetrics = []; + this.renderPowerMetricCharts(); + }); + }, + loadNodeMqttMetrics: function(nodeId) { + this.selectedNodeMqttMetrics = []; + window.axios.get(`/api/v1/nodes/${nodeId}/mqtt-metrics`).then((response) => { + this.selectedNodeMqttMetrics = response.data.mqtt_metrics; + }).catch(() => { + // do nothing + }); + }, + loadNodeTraceroutes: function(nodeId) { + this.selectedNodeTraceroutes = []; + window.axios.get(`/api/v1/nodes/${nodeId}/traceroutes`, { + params: { + count: 5, + }, + }).then((response) => { + this.selectedNodeTraceroutes = response.data.traceroutes; + }).catch(() => { + // do nothing + }); + }, + loadNodePositionHistory: function(nodeId) { + this.selectedNodePositionHistory = []; + window.axios.get(`/api/v1/nodes/${nodeId}/position-history`, { + params: { + // parse from datetime-local format, and send as unix timestamp in milliseconds + time_from: moment(this.positionHistoryDateTimeFrom, "YYYY-MM-DDTHH:mm").format("x"), + time_to: moment(this.positionHistoryDateTimeTo, "YYYY-MM-DDTHH:mm").format("x"), + }, + }).then((response) => { + this.selectedNodePositionHistory = response.data.position_history; + if(this.selectedNodeToShowPositionHistory != null){ + clearAllPositionHistory(); + onPositionHistoryUpdated(response.data.position_history); + } + + }).catch(() => { + // do nothing + }); + }, + renderDeviceMetricCharts: function() { + try { + this.updateDeviceMetricsChart(); + } catch(e) { + console.log(e); + } + }, + updateDeviceMetricsChart: function() { + + // destroy existing chart + const chartElementId = "deviceMetricsChart"; + const existingChart = window.Chart.getChart(chartElementId); + if(existingChart != null){ + existingChart.destroy(); + } + + // get chart element + const chartElement = window.document.getElementById(chartElementId); + if(!chartElement){ + return; + } + + // create chart data + const labels = []; + const batteryMetrics = []; + const channelUtilizationMetrics = []; + const airUtilTxMetrics = []; + for(const deviceMetric of this.selectedNodeDeviceMetrics){ + labels.push(moment(deviceMetric.created_at)); + batteryMetrics.push(deviceMetric.battery_level); + channelUtilizationMetrics.push(deviceMetric.channel_utilization); + airUtilTxMetrics.push(deviceMetric.air_util_tx); + } + + // create chart + new window.Chart(chartElement, { + type: 'line', + data: { + labels: labels, + datasets: [ + { + label: 'Battery Level', + borderColor: '#3b82f6', + backgroundColor: '#3b82f6', + pointStyle: false, // no points + fill: false, + data: batteryMetrics, + }, + { + label: 'Channel Util', + borderColor: '#22c55e', + backgroundColor: '#22c55e', + showLine: false, // no lines between points + fill: false, + data: channelUtilizationMetrics, + }, + { + label: 'Air Util TX', + borderColor: '#f97316', + backgroundColor: '#f97316', + showLine: false, // no lines between points + fill: false, + data: airUtilTxMetrics, + + }, + ], + }, + options: { + responsive: true, + borderWidth: 2, + elements: { + point: { + radius: 2, + }, + }, + scales: { + x: { + position: 'top', + type: 'time', + time: { + unit: 'day', + displayFormats: { + day: 'MMM DD', // Jan 01 + }, + }, + }, + y: { + min: 0, + max: 101, // 101 is "Plugged In", need to include for tooltip to work + ticks: { + callback: (label) => `${label}%`, + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + mode: "index", + intersect: false, + callbacks: { + label: (item) => { + return `${item.dataset.label}: ${item.formattedValue}%`; + }, + }, + }, + }, + } + }); + + }, + renderEnvironmentMetricCharts: function() { + try { + this.updateEnvironmentMetricsChart(); + } catch(e) { + console.log(e); + } + }, + updateEnvironmentMetricsChart: function() { + + // destroy existing chart + const chartElementId = "environmentMetricsChart"; + const existingChart = window.Chart.getChart(chartElementId); + if(existingChart != null){ + existingChart.destroy(); + } + + // get chart element + const chartElement = window.document.getElementById(chartElementId); + if(!chartElement){ + return; + } + + // create chart data + const labels = []; + const temperatureMetrics = []; + const relativeHumidityMetrics = []; + const barometricPressureMetrics = []; + const iaqMetrics = []; + for(const deviceMetric of this.selectedNodeEnvironmentMetrics){ + labels.push(moment(deviceMetric.created_at)); + temperatureMetrics.push(deviceMetric.temperature); + relativeHumidityMetrics.push(deviceMetric.relative_humidity); + barometricPressureMetrics.push(deviceMetric.barometric_pressure); + iaqMetrics.push(deviceMetric.iaq); + } + + // create chart + new window.Chart(chartElement, { + type: 'line', + data: { + labels: labels, + datasets: [ + { + label: 'Temperature', + suffix: '°C', + borderColor: '#3b82f6', + backgroundColor: '#3b82f6', + pointStyle: false, // no points + fill: false, + data: temperatureMetrics, + yAxisID: 'y', + }, + { + label: 'Humidity', + suffix: '%', + borderColor: '#22c55e', + backgroundColor: '#22c55e', + pointStyle: false, // no points + fill: false, + data: relativeHumidityMetrics, + yAxisID: 'y', + }, + { + label: 'Pressure', + suffix: 'hPa', + borderColor: '#f97316', + backgroundColor: '#f97316', + pointStyle: false, // no points + fill: false, + data: barometricPressureMetrics, + yAxisID: 'y1', + + }, + { + label: 'IAQ', + suffix: 'IAQ', + borderColor: '#f472b6', + backgroundColor: '#f472b6', + pointStyle: false, // no points + fill: false, + data: iaqMetrics, + yAxisID: 'yIAQ', + + }, + ], + }, + options: { + responsive: true, + borderWidth: 2, + spanGaps: 1000 * 60 * 60 * 24, // only show lines between metrics with a 24 hour or less gap + elements: { + point: { + radius: 2, + }, + }, + scales: { + x: { + position: 'top', + type: 'time', + time: { + unit: 'day', + displayFormats: { + day: 'MMM DD', // Jan 01 + }, + }, + }, + y: { + min: -20, + max: 100, + }, + y1: { + min: 800, + max: 1100, + ticks: { + stepSize: 10, + callback: (label) => `${label} hPa`, + }, + position: 'right', + grid: { + drawOnChartArea: false, // only want the grid lines for one axis to show up + }, + }, + yIAQ: { + type: 'linear', + display: false, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + mode: "index", + intersect: false, + callbacks: { + label: (item) => { + return `${item.dataset.label}: ${item.formattedValue}${item.dataset.suffix}`; + }, + }, + }, + }, + } + }); + + }, + renderPowerMetricCharts: function() { + try { + this.updatePowerMetricsChart(); + } catch(e) { + console.log(e); + } + }, + updatePowerMetricsChart: function() { + + // destroy existing chart + const chartElementId = "powerMetricsChart"; + const existingChart = window.Chart.getChart(chartElementId); + if(existingChart != null){ + existingChart.destroy(); + } + + // get chart element + const chartElement = window.document.getElementById(chartElementId); + if(!chartElement){ + return; + } + + // create chart data + const labels = []; + const channel1VoltageReadings = []; + const channel2VoltageReadings = []; + const channel3VoltageReadings = []; + const channel1CurrentReadings = []; + const channel2CurrentReadings = []; + const channel3CurrentReadings = []; + for(const powerMetric of this.selectedNodePowerMetrics){ + labels.push(moment(powerMetric.created_at)); + channel1VoltageReadings.push(powerMetric.ch1_voltage); + channel2VoltageReadings.push(powerMetric.ch2_voltage); + channel3VoltageReadings.push(powerMetric.ch3_voltage); + channel1CurrentReadings.push(powerMetric.ch1_current); + channel2CurrentReadings.push(powerMetric.ch2_current); + channel3CurrentReadings.push(powerMetric.ch3_current); + } + + // create chart + new window.Chart(chartElement, { + type: 'line', + data: { + labels: labels, + datasets: [ + { + label: 'Ch1 Voltage', + suffix: "V", + borderColor: '#3b82f6', + backgroundColor: '#3b82f6', + pointStyle: false, // no points + fill: false, + data: channel1VoltageReadings, + yAxisID: 'y', + }, + { + label: 'Ch2 Voltage', + suffix: "V", + borderColor: '#22c55e', + backgroundColor: '#22c55e', + pointStyle: false, // no points + fill: false, + data: channel2VoltageReadings, + yAxisID: 'y', + }, + { + label: 'Ch3 Voltage', + suffix: "V", + borderColor: '#f97316', + backgroundColor: '#f97316', + pointStyle: false, // no points + fill: false, + data: channel3VoltageReadings, + yAxisID: 'y', + }, + { + label: 'Ch1 Current', + suffix: "mA", + borderColor: '#93c5fd', + backgroundColor: '#93c5fd', + pointStyle: false, // no points + fill: false, + data: channel1CurrentReadings, + yAxisID: 'y1', + }, + { + label: 'Ch2 Current', + suffix: "mA", + borderColor: '#86efac', + backgroundColor: '#86efac', + pointStyle: false, // no points + fill: false, + data: channel2CurrentReadings, + yAxisID: 'y1', + }, + { + label: 'Ch3 Current', + suffix: "mA", + borderColor: '#fdba74', + backgroundColor: '#fdba74', + pointStyle: false, // no points + fill: false, + data: channel3CurrentReadings, + yAxisID: 'y1', + }, + ], + }, + options: { + responsive: true, + borderWidth: 2, + spanGaps: 1000 * 60 * 60 * 3, // only show lines between metrics with a 3 hour or less gap + elements: { + point: { + radius: 2, + }, + }, + scales: { + x: { + position: 'top', + type: 'time', + time: { + unit: 'day', + displayFormats: { + day: 'MMM DD', // Jan 01 + }, + }, + }, + y: { + min: 0, + suggestedMax: 6, + ticks: { + callback: (label) => `${label}V`, + }, + }, + y1: { + suggestedMin: -50, + suggestedMax: 50, + ticks: { + stepSize: 50, + callback: (label) => `${label}mA`, + }, + position: 'right', + grid: { + drawOnChartArea: false, // only want the grid lines for one axis to show up + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + mode: "index", + intersect: false, + callbacks: { + label: (item) => { + return `${item.dataset.label}: ${item.formattedValue}${item.dataset.suffix}`; + }, + }, + }, + }, + } + }); + + }, + showTraceRoute: function(traceroute) { + this.selectedTraceRoute = traceroute; + }, + findNodeById: function(id) { + return window.findNodeById(id); + }, + findNodeMarkerById: function(id) { + return window.findNodeMarkerById(id); + }, + onSearchResultNodeClick: function(node) { + + // clear search + this.searchText = ""; + + // hide search + this.isShowingMobileSearch = false; + + // go to node + if(window.goToNode(node.node_id)){ + return; + } + + // fallback to showing node details since we can't go to the node + window.showNodeDetails(node.node_id); + + }, + dismissInfoModal: function() { + this.isShowingInfoModal = false; + window.setConfigHasSeenInfoModal(true); + }, + getRegionFrequencyRange: function(regionName) { + return window.getRegionFrequencyRange(regionName); + }, + showNodePositionHistory: function(nodeId) { + + // find node + const node = findNodeById(nodeId); + if(!node){ + return; + } + + // update ui + this.selectedNode = null; + this.selectedNodeToShowPositionHistory = node; + this.isPositionHistoryModalExpanded = true; + + // close node info tooltip as position history shows under it + window.closeAllTooltips(); + + // reset default time range when opening position history ui + // YYYY-MM-DDTHH:mm is the format expected by the datetime-local input type + this.positionHistoryDateTimeFrom = moment().subtract(1, "hours").format('YYYY-MM-DDTHH:mm'); + this.positionHistoryDateTimeTo = moment().format('YYYY-MM-DDTHH:mm'); + + // load position history + this.loadNodePositionHistory(nodeId); + + }, + onPositionHistoryQuickRangeClick: function(range) { + + // update position history time range + switch(range){ + case "1h": { + this.positionHistoryDateTimeFrom = moment().subtract(1, "hours").format('YYYY-MM-DDTHH:mm'); + this.positionHistoryDateTimeTo = moment().format('YYYY-MM-DDTHH:mm'); + break; + } + case "24h": { + this.positionHistoryDateTimeFrom = moment().subtract(24, "hours").format('YYYY-MM-DDTHH:mm'); + this.positionHistoryDateTimeTo = moment().format('YYYY-MM-DDTHH:mm'); + break; + } + case "7d": { + this.positionHistoryDateTimeFrom = moment().subtract(7, "days").format('YYYY-MM-DDTHH:mm'); + this.positionHistoryDateTimeTo = moment().format('YYYY-MM-DDTHH:mm'); + break; + } + } + + // reload position history + const node = this.selectedNodeToShowPositionHistory; + if(node){ + this.loadNodePositionHistory(node.node_id); + } + + }, + getShareLinkForNode: function(nodeId) { + return window.location.origin + `/?node_id=${nodeId}`; + }, + copyShareLinkForNode: function(nodeId) { + + // make sure copy to clipboard is supported + if(!navigator.clipboard || !navigator.clipboard.writeText){ + alert("Clipboard not supported. Site must be served via https on iOS."); + return; + } + + // copy share link to clipboard + const url = this.getShareLinkForNode(nodeId); + navigator.clipboard.writeText(url); + + // tell user we copied it + alert("Link copied to clipboard!"); + + }, + dismissShowingNodeConnections: function() { + window._onHideNodeConnectionsClick(); + this.selectedNodeToShowConnections = null; + }, + dismissShowingNodePositionHistory: function() { + this.selectedNodePositionHistory = []; + this.selectedNodeToShowPositionHistory = null; + this.selectedNodePositionHistoryMarkers = []; + this.selectedNodePositionHistoryPolyLines = []; + cleanUpPositionHistory(); + }, + formatUptimeSeconds: function(secondsToFormat) { + secondsToFormat = Number(secondsToFormat); + var days = Math.floor(secondsToFormat / (3600 * 24)); + var hours = Math.floor((secondsToFormat % (3600 * 24)) / 3600); + var minutes = Math.floor((secondsToFormat % 3600) / 60); + var seconds = Math.floor(secondsToFormat % 60); + var daysPlural = days === 1 ? 'day' : 'days'; + return `${days} ${daysPlural} ${hours}h ${minutes}m ${seconds}s`; + }, + formatTemperature: function(celsius) { + switch(this.configTemperatureFormat){ + case "celsius": { + return `${Number(celsius).toFixed(0)}°C`; + } + case "fahrenheit": { + const fahrenheit = this.celsiusToFahrenheit(celsius); + return `${fahrenheit.toFixed(0)}°F`; + } + } + }, + convertTemperature: function(celsius) { + switch(this.configTemperatureFormat){ + case "celsius": { + return celsius; + } + case "fahrenheit": { + return this.celsiusToFahrenheit(celsius); + } + } + }, + getTemperatureUnit: function() { + switch(this.configTemperatureFormat){ + case "celsius": return "°C"; + case "fahrenheit": return "°F"; + } + }, + celsiusToFahrenheit: function(celsius) { + return (celsius * 9/5) + 32; + }, + getNodeColour(nodeId) { + // convert node id to a hex colour + return "#" + (nodeId & 0x00FFFFFF).toString(16).padStart(6, '0'); + }, + getNodeTextColour(nodeId) { + + // extract rgb components + const r = (nodeId & 0xFF0000) >> 16; + const g = (nodeId & 0x00FF00) >> 8; + const b = nodeId & 0x0000FF; + + // calculate brightness + const brightness = ((r * 0.299) + (g * 0.587) + (b * 0.114)) / 255; + + // determine text color based on brightness + return brightness > 0.5 ? "#000000" : "#FFFFFF"; + + }, + }, + computed: { + searchedNodes() { + + // search nodes + const nodes = this.nodes.filter((node) => { + const matchesId = node.node_id?.toLowerCase()?.includes(this.searchText.toLowerCase()); + const matchesHexId = node.node_id_hex?.toLowerCase()?.includes(this.searchText.toLowerCase()); + const matchesLongName = node.long_name?.toLowerCase()?.includes(this.searchText.toLowerCase()); + const matchesShortName = node.short_name?.toLowerCase()?.includes(this.searchText.toLowerCase()); + return matchesId || matchesHexId || matchesLongName || matchesShortName; + }); + + // order alphabetically by long name + nodes.sort((nodeA, nodeB) => { + const nodeALongName = nodeA.long_name || ""; + const nodeBLongName = nodeB.long_name || ""; + return nodeALongName.localeCompare(nodeBLongName); + }); + + // only return the first 500 results to avoid ui lag... + return nodes.slice(0, 500); + + }, + selectedNodeLatestPowerMetric() { + const [ latestPowerMetric ] = this.selectedNodePowerMetrics.slice(-1); + return latestPowerMetric; + }, + }, + watch: { + configNodesMaxAgeInSeconds() { + window.setConfigNodesMaxAgeInSeconds(this.configNodesMaxAgeInSeconds); + }, + configNodesOfflineAgeInSeconds() { + window.setConfigNodesOfflineAgeInSeconds(this.configNodesOfflineAgeInSeconds); + }, + configWaypointsMaxAgeInSeconds() { + window.setConfigWaypointsMaxAgeInSeconds(this.configWaypointsMaxAgeInSeconds); + }, + configConnectionsMaxDistanceInMeters() { + window.setConfigConnectionsMaxDistanceInMeters(this.configConnectionsMaxDistanceInMeters); + }, + configZoomLevelGoToNode() { + window.setConfigZoomLevelGoToNode(this.configZoomLevelGoToNode); + }, + configAutoUpdatePositionInUrl() { + window.setConfigAutoUpdatePositionInUrl(this.configAutoUpdatePositionInUrl); + }, + configEnableMapAnimations() { + window.setConfigEnableMapAnimations(this.configEnableMapAnimations); + }, + configTemperatureFormat() { + window.setConfigTemperatureFormat(this.configTemperatureFormat); + }, + configConnectionsTimePeriodInSeconds() { + window.setConfigConnectionsTimePeriodInSeconds(this.configConnectionsTimePeriodInSeconds); + }, + configConnectionsColoredLines() { + window.setConfigConnectionsColoredLines(this.configConnectionsColoredLines); + }, + configConnectionsBidirectionalOnly() { + window.setConfigConnectionsBidirectionalOnly(this.configConnectionsBidirectionalOnly); + }, + configConnectionsMinSnrDb() { + window.setConfigConnectionsMinSnrDb(this.configConnectionsMinSnrDb); + }, + configConnectionsBidirectionalMinSnr() { + window.setConfigConnectionsBidirectionalMinSnr(this.configConnectionsBidirectionalMinSnr); + }, + deviceMetricsTimeRange() { + this.loadNodeDeviceMetrics(this.selectedNode.node_id); + }, + environmentMetricsTimeRange() { + this.loadNodeEnvironmentMetrics(this.selectedNode.node_id); + }, + powerMetricsTimeRange() { + this.loadNodePowerMetrics(this.selectedNode.node_id); + }, + }, +}).mount('#app'); \ No newline at end of file diff --git a/src/public/assets/js/config.js b/src/public/assets/js/config.js new file mode 100644 index 0000000..5866a4c --- /dev/null +++ b/src/public/assets/js/config.js @@ -0,0 +1,199 @@ +function getConfigHasSeenInfoModal() { + return localStorage.getItem("config_has_seen_info_modal") === "true"; +} + +function setConfigHasSeenInfoModal(value) { + return localStorage.setItem("config_has_seen_info_modal", value); +} + +function getConfigAutoUpdatePositionInUrl() { + // use user preference, or enable by default + const value = localStorage.getItem("config_auto_update_position_in_url"); + return value === "true" || value == null; +} + +function setConfigAutoUpdatePositionInUrl(value) { + return localStorage.setItem("config_auto_update_position_in_url", value); +} + +function getConfigEnableMapAnimations() { + + const value = localStorage.getItem("config_enable_map_animations"); + + // enable animations by default + if(value === null){ + return true; + } + + return value === "true"; + +} + +function setConfigEnableMapAnimations(value) { + return localStorage.setItem("config_enable_map_animations", value); +} + +function getConfigTemperatureFormat() { + return localStorage.getItem("config_temperature_format") || "celsius"; +} + +function setConfigTemperatureFormat(format) { + return localStorage.setItem("config_temperature_format", format); +} + +function getConfigMapSelectedTileLayer() { + return localStorage.getItem("config_map_selected_tile_layer") || "Thunderforest Neighbourhood"; +} + +function setConfigMapSelectedTileLayer(layer) { + return localStorage.setItem("config_map_selected_tile_layer", layer); +} + +function getConfigMapEnabledOverlayLayers() { + + try { + const value = localStorage.getItem("config_map_enabled_overlay_layers"); + if(value){ + return JSON.parse(value); + } + } catch(e) {} + + // overlays enabled by default + return ["Legend", "Position History", "Traceroutes"]; + +} + +function setConfigMapEnabledOverlayLayers(layers) { + return localStorage.setItem("config_map_enabled_overlay_layers", JSON.stringify(layers)); +} + +function getConfigNodesMaxAgeInSeconds() { + const value = localStorage.getItem("config_nodes_max_age_in_seconds"); + return value != null ? parseInt(value) : null; +} + +function setConfigNodesMaxAgeInSeconds(value) { + if(value != null){ + return localStorage.setItem("config_nodes_max_age_in_seconds", value); + } else { + return localStorage.removeItem("config_nodes_max_age_in_seconds"); + } +} + +function getConfigNodesOfflineAgeInSeconds() { + const value = localStorage.getItem("config_nodes_offline_age_in_seconds"); + return value != null ? parseInt(value) : 10800; +} + +function setConfigNodesOfflineAgeInSeconds(value) { + if(value != null){ + return localStorage.setItem("config_nodes_offline_age_in_seconds", value); + } else { + return localStorage.removeItem("config_nodes_offline_age_in_seconds"); + } +} + +function getConfigWaypointsMaxAgeInSeconds() { + const value = localStorage.getItem("config_waypoints_max_age_in_seconds"); + return value != null ? parseInt(value) : null; +} + +function setConfigWaypointsMaxAgeInSeconds(value) { + if(value != null){ + return localStorage.setItem("config_waypoints_max_age_in_seconds", value); + } else { + return localStorage.removeItem("config_waypoints_max_age_in_seconds"); + } +} + +function getConfigConnectionsMaxDistanceInMeters() { + const value = localStorage.getItem("config_connections_max_distance_in_meters"); + // default to 70km (70,000 meters) + return value != null ? parseInt(value) : 70000; +} + +function setConfigConnectionsMaxDistanceInMeters(value) { + return localStorage.setItem("config_connections_max_distance_in_meters", value); +} + +function getConfigZoomLevelGoToNode() { + const value = localStorage.getItem("config_zoom_level_go_to_node"); + const parsedValue = value != null ? parseInt(value) : null; + return parsedValue || 15; +} + +function setConfigZoomLevelGoToNode(value) { + return localStorage.setItem("config_zoom_level_go_to_node", value); +} + +function getConfigConnectionsTimePeriodInSeconds() { + const value = localStorage.getItem("config_connections_time_period_in_seconds"); + // default to 7 days if unset + return value != null ? parseInt(value) : 604800; +} + +function setConfigConnectionsTimePeriodInSeconds(value) { + return localStorage.setItem("config_connections_time_period_in_seconds", value); +} + +function getConfigConnectionsColoredLines() { + const value = localStorage.getItem("config_connections_colored_lines"); + // disable colored lines by default + if(value === null){ + return false; + } + return value === "true"; +} + +function setConfigConnectionsColoredLines(value) { + return localStorage.setItem("config_connections_colored_lines", value); +} + +function getConfigConnectionsBidirectionalOnly() { + const value = localStorage.getItem("config_connections_bidirectional_only"); + // disable bidirectional filter by default + if(value === null){ + return false; + } + return value === "true"; +} + +function setConfigConnectionsBidirectionalOnly(value) { + return localStorage.setItem("config_connections_bidirectional_only", value); +} + +function getConfigConnectionsMinSnrDb() { + const value = localStorage.getItem("config_connections_min_snr_db"); + // default to null (unset) + if(value === null || value === ""){ + return null; + } + const parsed = parseFloat(value); + return isNaN(parsed) ? null : parsed; +} + +function setConfigConnectionsMinSnrDb(value) { + if(value === null || value === "" || value === undefined){ + return localStorage.removeItem("config_connections_min_snr_db"); + } + // Convert to string for localStorage (handles both number and string inputs) + const stringValue = typeof value === "number" ? value.toString() : String(value); + return localStorage.setItem("config_connections_min_snr_db", stringValue); +} + +function getConfigConnectionsBidirectionalMinSnr() { + const value = localStorage.getItem("config_connections_bidirectional_min_snr"); + // disable bidirectional minimum SNR by default + if(value === null){ + return false; + } + return value === "true"; +} + +function setConfigConnectionsBidirectionalMinSnr(value) { + return localStorage.setItem("config_connections_bidirectional_min_snr", value); +} + +function isMobile() { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); +} \ No newline at end of file diff --git a/src/public/assets/js/map.js b/src/public/assets/js/map.js new file mode 100644 index 0000000..e25c067 --- /dev/null +++ b/src/public/assets/js/map.js @@ -0,0 +1,1692 @@ +// global state +var nodes = []; +var nodeMarkers = {}; +var selectedNodeOutlineCircle = null; +var waypoints = []; + +// set map bounds to be a little more than full size to prevent panning off screen +var bounds = [ + [-100, 70], // top left + [100, 500], // bottom right +]; + +// create map positioned over NRW +if(!isMobile()){ + var map = L.map('map', { + maxBounds: bounds, + }).setView([ + 51.1, + 366.82, + ], 9); +} else { + var map = L.map('map', { + maxBounds: bounds, + }).setView([ + 51.1, + 366.82, + ], 8); +} + +// remove leaflet link +map.attributionControl.setPrefix(''); + +var openThunderforestLandscapeMapTileLayer = L.tileLayer('https://tiles.nixware.dev/landscape/{z}/{x}/{y}.png', { + maxZoom: 22, + attribution: 'Tiles © Gravitystorm Limited | Data from Meshtastic', +}); + +var openThunderforestAtlasMapTileLayer = L.tileLayer('https://tiles.nixware.dev/atlas/{z}/{x}/{y}.png', { + maxZoom: 22, + attribution: 'Tiles © Gravitystorm Limited | Data from Meshtastic', +}); + +var openThunderforestNeighbourhoodMapTileLayer = L.tileLayer('https://tiles.nixware.dev/neighbourhood/{z}/{x}/{y}.png', { + maxZoom: 22, + attribution: 'Tiles © Gravitystorm Limited | Data from Meshtastic', +}); + +var openStreetMapTileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 22, // increase from 18 to 22 + attribution: 'Tiles © OpenStreetMap | Data from Meshtastic', +}); + +var openTopoMapTileLayer = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', { + maxZoom: 17, // open topo map doesn't have tiles closer than this + attribution: 'Tiles © OpenStreetMap | Data from Meshtastic', +}); + +var esriWorldImageryTileLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { + maxZoom: 21, // esri doesn't have tiles closer than this + attribution: 'Tiles © Esri | Data from Meshtastic' +}); + +var googleSatelliteTileLayer = L.tileLayer('https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', { + maxZoom: 21, + subdomains: ['mt0', 'mt1', 'mt2', 'mt3'], + attribution: 'Tiles © Google | Data from Meshtastic' +}); + +var googleHybridTileLayer = L.tileLayer('https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', { + maxZoom: 21, + subdomains: ['mt0', 'mt1', 'mt2', 'mt3'], + attribution: 'Tiles © Google | Data from Meshtastic' +}); + +var tileLayers = { + "Thunderforest Neighbourhood": openThunderforestNeighbourhoodMapTileLayer, + "Thunderforest Landscape": openThunderforestLandscapeMapTileLayer, + "Thunderforest Atlas": openThunderforestAtlasMapTileLayer, + "OpenStreetMap": openStreetMapTileLayer, + "OpenTopoMap": openTopoMapTileLayer, + "Esri Satellite": esriWorldImageryTileLayer, + "Google Satellite": googleSatelliteTileLayer, + "Google Hybrid": googleHybridTileLayer, +}; + +// use tile layer based on config +const selectedTileLayerName = getConfigMapSelectedTileLayer(); +const selectedTileLayer = tileLayers[selectedTileLayerName] || openThunderforestNeighbourhoodMapTileLayer; +selectedTileLayer.addTo(map); + +// create layer groups +var nodesLayerGroup = new L.LayerGroup(); +var backboneConnectionsLayerGroup = new L.LayerGroup(); +var nodeConnectionsLayerGroup = new L.LayerGroup(); +var nodesClusteredLayerGroup = L.markerClusterGroup({ + showCoverageOnHover: false, + disableClusteringAtZoom: 10, // zoom level where node clustering is disabled +}); +var nodesRouterLayerGroup = L.markerClusterGroup({ + showCoverageOnHover: false, + disableClusteringAtZoom: 10, // zoom level where node clustering is disabled +}); +var nodesBackboneLayerGroup = new L.LayerGroup(); +//var nodesMediumFastLayerGroup = new L.LayerGroup(); +var nodesShortSlowLayerGroup = new L.LayerGroup(); +var nodesLongFastLayerGroup = new L.LayerGroup(); +var waypointsLayerGroup = new L.LayerGroup(); +var nodePositionHistoryLayerGroup = new L.LayerGroup(); +var traceroutesLayerGroup = new L.LayerGroup(); +var connectionsLayerGroup = new L.LayerGroup(); + +// create icons +var iconMqttConnected = L.divIcon({ + className: 'icon-mqtt-connected', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +}); + +var iconLongFast = L.divIcon({ + className: 'icon-longfast', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +}); + +/*var iconMediumFast = L.divIcon({ + className: 'icon-mediumfast', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +});*/ + +var iconShortSlow = L.divIcon({ + className: 'icon-shortslow', + iconSize: [16, 16], +}); + +var iconMqttDisconnected = L.divIcon({ + className: 'icon-mqtt-disconnected', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +}); + +var iconOffline = L.divIcon({ + className: 'icon-offline', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +}); + +var iconPositionHistory = L.divIcon({ + className: 'icon-position-history', + iconSize: [16, 16], // increase from 12px to 16px to make hover easier +}); + +var iconTracerouteStart = L.divIcon({ + className: 'icon-traceroute-start', + iconSize: [16, 16], +}); + +var iconTracerouteEnd = L.divIcon({ + className: 'icon-traceroute-end', + iconSize: [16, 16], +}); + +// create legend +var legendLayerGroup = new L.LayerGroup(); +var legend = L.control({position: 'bottomleft'}); +legend.onAdd = function (map) { + var div = L.DomUtil.create('div', 'leaflet-control-layers'); + div.style.backgroundColor = 'white'; + div.style.padding = '12px'; + div.innerHTML = `
Legend
` + + `
ShortSlow
` + //+ `
MediumFast
` + + `
LongFast
` + + `
Offline Too Long
` + + `
Traceroute
`; + return div; +}; + +// handle baselayerchange to update tile layer preference +map.on('baselayerchange', function(event) { + setConfigMapSelectedTileLayer(event.name); +}); + +// handle adding/remove legend on map (can't use L.Control as an overlay, so we toggle an empty L.LayerGroup) +map.on('overlayadd overlayremove', function(event) { + if(event.name === "Legend"){ + if(event.type === "overlayadd"){ + map.addControl(legend); + } else if(event.type === "overlayremove"){ + map.removeControl(legend); + } + } +}); + +// add layers to control ui +L.control.groupedLayers(tileLayers, { + "Nodes": { + "All": nodesLayerGroup, + "Routers": nodesRouterLayerGroup, + "Backbone": nodesBackboneLayerGroup, + "ShortSlow": nodesShortSlowLayerGroup, + //"MediumFast": nodesMediumFastLayerGroup, + "LongFast": nodesLongFastLayerGroup, + "Clustered": nodesClusteredLayerGroup, + "None": new L.LayerGroup(), + }, + "Overlays": { + "Legend": legendLayerGroup, + "Backbone Connections": backboneConnectionsLayerGroup, + "Connections": connectionsLayerGroup, + "Waypoints": waypointsLayerGroup, + "Position History": nodePositionHistoryLayerGroup, + "Traceroutes": traceroutesLayerGroup, + }, +}, { + // make the "Nodes" group exclusive (use radio inputs instead of checkbox) + exclusiveGroups: ["Nodes"], +}).addTo(map); + +// enable base layers +nodesLayerGroup.addTo(map); + +// enable overlay layers based on config +const enabledOverlayLayers = getConfigMapEnabledOverlayLayers(); +if(enabledOverlayLayers.includes("Legend")){ + legendLayerGroup.addTo(map); +} +if(enabledOverlayLayers.includes("Backbone Connection")){ + backboneConnectionsLayerGroup.addTo(map); +} +if(enabledOverlayLayers.includes("Connections")){ + connectionsLayerGroup.addTo(map); +} +if(enabledOverlayLayers.includes("Waypoints")){ + waypointsLayerGroup.addTo(map); +} +if(enabledOverlayLayers.includes("Position History")){ + nodePositionHistoryLayerGroup.addTo(map); +} +if(enabledOverlayLayers.includes("Traceroutes")){ + traceroutesLayerGroup.addTo(map); +} + +map.on('overlayadd', function(event) { + // update config when map overlay is added + const layerName = event.name; + const enabledOverlayLayers = getConfigMapEnabledOverlayLayers(); + if(!enabledOverlayLayers.includes(layerName)){ + enabledOverlayLayers.push(layerName); + } + setConfigMapEnabledOverlayLayers(enabledOverlayLayers); + + // clear traceroutes layer when traceroutes overlay is added + if (layerName === "Traceroutes") { + traceroutesLayerGroup.clearLayers(); + } +}); + +// update config when map overlay is removed +map.on('overlayremove', function(event) { + const layerName = event.name; + const enabledOverlayLayers = getConfigMapEnabledOverlayLayers().filter(function(enabledOverlayLayer) { + return enabledOverlayLayer !== layerName; + }); + setConfigMapEnabledOverlayLayers(enabledOverlayLayers); +}); + +// handle map clicks +map.on('click', function() { + + // remove outline when map clicked + clearNodeOutline(); + + // send callback to vue + window._onMapClick(); + +}); + +// close all tooltips and popups when clicking map +map.on("click", function(event) { + + // do nothing when clicking inside tooltip + const clickedElement = event.originalEvent.target; + if(elementOrAnyAncestorHasClass(clickedElement, "leaflet-tooltip")){ + return; + } + + closeAllTooltips(); + closeAllPopups(); + +}); + +function isValidLatLng(lat, lng) { + + if(isNaN(lat) || isNaN(lng)){ + return false; + } + + return true; + +} + +function findNodeById(id) { + + // find node by id + var node = nodes.find((node) => node.node_id.toString() === id.toString()); + if(node){ + return node; + } + + return null; + +} + +function findNodeMarkerById(id) { + + // find node marker by id + var nodeMarker = nodeMarkers[id]; + if(nodeMarker){ + return nodeMarker; + } + + return null; + +} + +function goToNode(id, animate, zoom){ + + // find node + var node = findNodeById(id); + if(!node){ + alert("Could not find node: " + id); + return false; + } + + // find node marker by id + var nodeMarker = findNodeMarkerById(id); + if(!nodeMarker){ + return false; + } + + // close all popups and tooltips + closeAllPopups(); + closeAllTooltips(); + + // select node + showNodeOutline(id); + + // fly to node marker + const shouldAnimate = animate != null ? animate : true; + map.flyTo(nodeMarker.getLatLng(), zoom || getConfigZoomLevelGoToNode(), { + animate: getConfigEnableMapAnimations() ? shouldAnimate : false, + }); + + // open tooltip for node + map.openTooltip(getTooltipContentForNode(node), nodeMarker.getLatLng(), { + interactive: true, // allow clicking buttons inside tooltip + permanent: true, // don't auto dismiss when clicking buttons inside tooltip + }); + + // successfully went to node + return true; + +} + +function goToRandomNode() { + if(nodes.length > 0){ + const randomNode = nodes[Math.floor(Math.random() * nodes.length)]; + if(randomNode){ + + // go to node + if(window.goToNode(randomNode.node_id)){ + return; + } + + // fallback to showing node details since we can't go to the node + window.showNodeDetails(randomNode.node_id); + + } + } +} + +function clearAllNodes() { + nodesLayerGroup.clearLayers(); + nodesClusteredLayerGroup.clearLayers(); + nodesRouterLayerGroup.clearLayers(); + nodesBackboneLayerGroup.clearLayers(); + nodesShortSlowLayerGroup.clearLayers(); + //nodesMediumFastLayerGroup.clearLayers(); + nodesLongFastLayerGroup.clearLayers(); +} + +function clearAllBackboneConnections() { + backboneConnectionsLayerGroup.clearLayers(); +} + +function clearAllWaypoints() { + waypointsLayerGroup.clearLayers(); +} + +function clearAllTraceroutes() { + traceroutesLayerGroup.clearLayers(); +} + +function clearAllConnections() { + connectionsLayerGroup.clearLayers(); + backboneConnectionsLayerGroup.clearLayers(); +} + +function closeAllPopups() { + map.eachLayer(function(layer) { + if(layer.options.pane === "popupPane"){ + layer.removeFrom(map); + } + }); +} + +function closeAllTooltips() { + map.eachLayer(function(layer) { + if(layer.options.pane === "tooltipPane"){ + layer.removeFrom(map); + } + }); +} + +function clearAllPositionHistory() { + nodePositionHistoryLayerGroup.clearLayers(); +} + +function clearNodeOutline() { + if(selectedNodeOutlineCircle){ + selectedNodeOutlineCircle.removeFrom(map); + selectedNodeOutlineCircle = null; + } +} + +function showNodeOutline(id) { + + // remove any existing node circle + clearNodeOutline(); + + // find node marker by id + const nodeMarker = nodeMarkers[id]; + if(!nodeMarker){ + return; + } + + // find node by id + const node = findNodeById(id); + if(!node){ + return; + } + + // add position precision circle around node + if(node.position_precision != null && node.position_precision > 0 && node.position_precision < 32){ + selectedNodeOutlineCircle = L.circle(nodeMarker.getLatLng(), { + radius: getPositionPrecisionInMeters(node.position_precision), + }).addTo(map); + } + +} + +function showNodeDetails(id) { + + // find node + const node = findNodeById(id); + if(!node){ + return; + } + + // fire callback to vuejs handler + window._onNodeClick(node); + +} + +function getColourForSnr(snr) { + if(snr >= -4) return "#16a34a"; // good + if(snr > -8) return "#fff200"; // medium-good + if(snr > -12) return "#ff9f1c"; // medium + return "#dc2626"; // bad +} + +function getSignalBarsIndicator(snrDb) { + if(snrDb == null) return ''; + + // Determine number of bars based on SNR + let bars = 0; + if(snrDb >= -4) bars = 4; // good + else if(snrDb > -8) bars = 3; // medium-good + else if(snrDb > -12) bars = 2; // medium + else bars = 1; // bad + + const color = getColourForSnr(snrDb); + + // Create 4 bars with increasing height + let indicator = ''; + + // Bar heights: 4px, 6px, 8px, 10px + const barHeights = [4, 6, 8, 10]; + const barWidth = 2; + + for (let i = 0; i < 4; i++) { + const height = barHeights[i]; + const isActive = i < bars; + const barColor = isActive ? color : '#d1d5db'; // gray for inactive bars + indicator += ``; + } + + indicator += ''; + return indicator; +} + +function cleanUpNodeConnections() { + + // close tooltips and popups + closeAllPopups(); + closeAllTooltips(); + + // setup node connections layer + nodeConnectionsLayerGroup.clearLayers(); + nodeConnectionsLayerGroup.removeFrom(map); + nodeConnectionsLayerGroup.addTo(map); + +} + +function getTerrainProfileImage(node1, node2) { + + // line colour between nodes + const lineColour = "0000FF"; // blue + + // node 1 (left side of image) + const node1MarkerColour = "0000FF"; // blue + const node1Latitude = node1.latitude; + const node1Longitude = node1.longitude; + const node1ElevationMSL = node1.altitude ?? ""; + + // node 2 (right side of image) + const node2MarkerColour = "0000FF"; // blue + const node2Latitude = node2.latitude; + const node2Longitude = node2.longitude; + const node2ElevationMSL = node2.altitude ?? ""; + + // generate terrain profile image url + return "https://heywhatsthat.com/bin/profile-0904.cgi?" + new URLSearchParams({ + src: "meshtastic.liamcottle.net", + axes: 1, // include grid lines and a scale + metric: 1, // show metric units + curvature: 1, + width: 500, + height: 200, + pt0: `${node1Latitude},${node1Longitude},${lineColour},${node1ElevationMSL},${node1MarkerColour}`, + pt1: `${node2Latitude},${node2Longitude},${lineColour},${node2ElevationMSL},${node2MarkerColour}`, + }).toString(); + +} + +async function showNodeConnections(id) { + + cleanUpNodeConnections(); + + // find node + const node = findNodeById(id); + if(!node){ + return; + } + + // find node marker + const nodeMarker = findNodeMarkerById(node.node_id); + if(!nodeMarker){ + return; + } + + // show overlay for node connections + window._onShowNodeConnectionsClick(node); + + // Fetch connections for this node + const connectionsTimePeriodSec = getConfigConnectionsTimePeriodInSeconds(); + const connectionsTimeFrom = connectionsTimePeriodSec ? (Date.now() - connectionsTimePeriodSec * 1000) : undefined; + const connectionsParams = new URLSearchParams(); + connectionsParams.set('node_id', id); + if (connectionsTimeFrom) connectionsParams.set('time_from', connectionsTimeFrom); + + try { + const response = await window.axios.get(`/api/v1/connections?${connectionsParams.toString()}`); + const connections = response.data.connections ?? []; + + for (const connection of connections) { + // Convert to numbers for comparison since API returns strings + const nodeA = parseInt(connection.node_a, 10); + const nodeB = parseInt(connection.node_b, 10); + + const otherNodeId = nodeA === id ? nodeB : nodeA; + const otherNode = findNodeById(otherNodeId); + const otherNodeMarker = findNodeMarkerById(otherNodeId); + + if (!otherNode || !otherNodeMarker) continue; + + // Apply bidirectional filter + const configConnectionsBidirectionalOnly = getConfigConnectionsBidirectionalOnly(); + if(configConnectionsBidirectionalOnly){ + const hasDirectionAB = connection.direction_ab && connection.direction_ab.avg_snr_db != null; + const hasDirectionBA = connection.direction_ba && connection.direction_ba.avg_snr_db != null; + if(!hasDirectionAB || !hasDirectionBA){ + continue; + } + } + + // Apply minimum SNR filter + const configConnectionsMinSnrDb = getConfigConnectionsMinSnrDb(); + if(configConnectionsMinSnrDb != null){ + const snrAB = connection.direction_ab && connection.direction_ab.avg_snr_db != null ? connection.direction_ab.avg_snr_db : null; + const snrBA = connection.direction_ba && connection.direction_ba.avg_snr_db != null ? connection.direction_ba.avg_snr_db : null; + + const configConnectionsBidirectionalMinSnr = getConfigConnectionsBidirectionalMinSnr(); + let hasSnrAboveThreshold; + + if(configConnectionsBidirectionalMinSnr){ + // Bidirectional mode: ALL existing directions must meet threshold + const directionsToCheck = []; + if(snrAB != null) directionsToCheck.push(snrAB); + if(snrBA != null) directionsToCheck.push(snrBA); + + if(directionsToCheck.length === 0){ + // No SNR data in either direction, skip + hasSnrAboveThreshold = false; + } else { + // All existing directions must be above threshold + hasSnrAboveThreshold = directionsToCheck.every(snr => snr > configConnectionsMinSnrDb); + } + } else { + // Default mode: EITHER direction has SNR above threshold + hasSnrAboveThreshold = (snrAB != null && snrAB > configConnectionsMinSnrDb) || (snrBA != null && snrBA > configConnectionsMinSnrDb); + } + + if(!hasSnrAboveThreshold){ + continue; + } + } + + // Calculate distance + const distanceInMeters = nodeMarker.getLatLng().distanceTo(otherNodeMarker.getLatLng()).toFixed(2); + const configConnectionsMaxDistanceInMeters = getConfigConnectionsMaxDistanceInMeters(); + if(configConnectionsMaxDistanceInMeters != null && parseFloat(distanceInMeters) > configConnectionsMaxDistanceInMeters){ + continue; + } + + let distance = `${distanceInMeters} meters`; + if (distanceInMeters >= 1000) { + const distanceInKilometers = (distanceInMeters / 1000).toFixed(2); + distance = `${distanceInKilometers} kilometers`; + } + + // Determine line color + const configConnectionsColoredLines = getConfigConnectionsColoredLines(); + const worstSnrDb = connection.worst_avg_snr_db; + const lineColor = configConnectionsColoredLines && worstSnrDb != null ? getColourForSnr(worstSnrDb) : '#2563eb'; + + // Create bidirectional line + const line = L.polyline([ + nodeMarker.getLatLng(), + otherNodeMarker.getLatLng(), + ], { + color: lineColor, + opacity: 0.75, + weight: 3, + }).addTo(nodeConnectionsLayerGroup); + + // Generate tooltip using standardized function + const tooltipNodeA = findNodeById(connection.node_a); + const tooltipNodeB = findNodeById(connection.node_b); + const tooltip = generateConnectionTooltip(connection, tooltipNodeA, tooltipNodeB, distance); + + line.bindTooltip(tooltip, { + sticky: true, + opacity: 1, + interactive: true, + }) + .bindPopup(tooltip) + .on('click', function(event) { + event.target.closeTooltip(); + }); + } + } catch (err) { + console.error('Error fetching connections:', err); + } + +} + +function clearMap() { + closeAllPopups(); + closeAllTooltips(); + clearAllNodes(); + clearAllBackboneConnections(); + clearAllWaypoints(); + clearAllTraceroutes(); + clearAllConnections(); + clearNodeOutline(); + cleanUpNodeConnections(); +} + +// returns true if the element or one of its parents has the class classname +function elementOrAnyAncestorHasClass(element, className) { + + // check if element contains class + if(element.classList && element.classList.contains(className)){ + return true; + } + + // check if parent node has the class + if(element.parentNode){ + return elementOrAnyAncestorHasClass(element.parentNode, className); + } + + // couldn't find the class + return false; + +} + +// escape strings for tooltips etc, to prevent html/script injection +// not used in vuejs, as that auto escapes +function escapeString(string) { + return string.replace(//g, ">"); +} + + +function onNodesUpdated(updatedNodes) { + + // clear nodes cache + nodes = []; + + // get config + const now = moment(); + const configNodesMaxAgeInSeconds = getConfigNodesMaxAgeInSeconds(); + const configNodesOfflineAgeInSeconds = getConfigNodesOfflineAgeInSeconds(); + const configConnectionsMaxDistanceInMeters = getConfigConnectionsMaxDistanceInMeters(); + + // add nodes + for(const node of updatedNodes){ + + // skip nodes older than configured node max age + if(configNodesMaxAgeInSeconds){ + const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at)); + if(lastUpdatedAgeInMillis > configNodesMaxAgeInSeconds * 1000){ + continue; + } + } + + // add to cache + nodes.push(node); + + // skip nodes without position + if(!node.latitude || !node.longitude){ + continue; + } + + // fix lat long + node.latitude = node.latitude / 10000000; + node.longitude = node.longitude / 10000000; + + // skip nodes with invalid position + if(!isValidLatLng(node.latitude, node.longitude)){ + continue; + } + + // wrap longitude for shortest path, everything to left of australia should be shown on the right + var longitude = parseFloat(node.longitude); + if(longitude <= 100){ + longitude += 360; + } + + // icon based on channel preset + var icon = iconLongFast; + + if (node.channel_id == "ShortSlow") { + icon = iconShortSlow; + } + + /*if (node.channel_id == "MediumFast") { + icon = iconMediumFast; + }*/ + + // use offline icon for nodes older than configured node offline age + if(configNodesOfflineAgeInSeconds){ + const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at)); + if(lastUpdatedAgeInMillis > configNodesOfflineAgeInSeconds * 1000){ + icon = iconOffline; + } + } + + // determine zIndexOffset: MediumFast (1000), LongFast (-1000), Offline (-2000) + var zIndexOffset = 1000; + if(icon == iconOffline){ + zIndexOffset = -2000; + } else if(node.channel_id == 'LongFast'){ + zIndexOffset = -1000; + } + + // To not have overlapping nodes. + var latJitter = 0; + var lonJitter = 0; + // If position pression > 45m apply random jitter within a small circle to avoid diagonal-only displacement + if (node.position_precision < 19) { + const maxMeters = 40; + const r = maxMeters * Math.sqrt(Math.random()); + const theta = 2 * Math.PI * Math.random(); + const dy = r * Math.sin(theta); + const dx = r * Math.cos(theta); + const metersPerDegLat = 111320; + const metersPerDegLon = 111320 * Math.cos(node.latitude * Math.PI / 180); + latJitter = dy / metersPerDegLat; + lonJitter = metersPerDegLon ? (dx / metersPerDegLon) : 0; + } + + // create node marker + const marker = L.marker([node.latitude + latJitter, longitude + lonJitter], { + icon: icon, + tagName: node.node_id, + // zIndex: offline (-2000) < has channel_id (-1000) < others (1000) + zIndexOffset: zIndexOffset, + }).on('click', function(event) { + // close tooltip on click to prevent tooltip and popup showing at same time + event.target.closeTooltip(); + }); + + // add marker to node layer groups + marker.addTo(nodesLayerGroup); + nodesClusteredLayerGroup.addLayer(marker); + + // add markers for routers and repeaters to routers layer group + if(node.role_name === "ROUTER" + || node.role_name === "ROUTER_CLIENT" + || node.role_name === "ROUTER_LATE" + || node.role_name === "REPEATER"){ + nodesRouterLayerGroup.addLayer(marker); + } + + // add markers for backbone to layer group + if(node.is_backbone) { + nodesBackboneLayerGroup.addLayer(marker); + } + + if(node.channel_id == "ShortSlow") { + nodesShortSlowLayerGroup.addLayer(marker); + } + + // add markers for MediumFast channel to layer group + /*if(node.channel_id == "MediumFast") { + nodesMediumFastLayerGroup.addLayer(marker); + }*/ + + // add markers for LongFast channel to layer group + if(node.channel_id == "LongFast") { + nodesLongFastLayerGroup.addLayer(marker); + } + + // show tooltip on desktop only + if(!isMobile()){ + marker.bindTooltip(getTooltipContentForNode(node), { + interactive: true, + }); + } + + // show node info tooltip when clicking node marker + marker.on("click", function(event) { + + // close all other popups and tooltips + closeAllTooltips(); + closeAllPopups(); + + // find node + const node = findNodeById(event.target.options.tagName); + if(!node){ + return; + } + + // show position precision outline + showNodeOutline(node.node_id); + + // open tooltip for node + map.openTooltip(getTooltipContentForNode(node), event.target.getLatLng(), { + interactive: true, // allow clicking buttons inside tooltip + permanent: true, // don't auto dismiss when clicking buttons inside tooltip + }); + + }); + + // add to cache + nodeMarkers[node.node_id] = marker; + + } + + window._onNodesUpdated(nodes); + +} + +function onWaypointsUpdated(updatedWaypoints) { + + // clear nodes cache + waypoints = []; + + // get config + const now = moment(); + const configWaypointsMaxAgeInSeconds = getConfigWaypointsMaxAgeInSeconds(); + + // add nodes + for(const waypoint of updatedWaypoints){ + + // skip waypoints older than configured waypoint max age + if(configWaypointsMaxAgeInSeconds){ + const lastUpdatedAgeInMillis = now.diff(moment(waypoint.updated_at)); + if(lastUpdatedAgeInMillis > configWaypointsMaxAgeInSeconds * 1000){ + continue; + } + } + + // skip expired waypoints + if(waypoint.expire < Date.now() / 1000){ + continue; + } + + // skip waypoints without position + if(!waypoint.latitude || !waypoint.longitude){ + continue; + } + + // fix lat long + waypoint.latitude = waypoint.latitude / 10000000; + waypoint.longitude = waypoint.longitude / 10000000; + + // skip waypoints with invalid position + if(!isValidLatLng(waypoint.latitude, waypoint.longitude)){ + continue; + } + + // wrap longitude for shortest path, everything to left of australia should be shown on the right + var longitude = parseFloat(waypoint.longitude); + if(longitude <= 100){ + longitude += 360; + } + + // determine emoji to show as marker icon + const emoji = waypoint.icon === 0 ? 128205 : waypoint.icon; + const emojiText = String.fromCodePoint(emoji) + + var tooltip = getTooltipContentForWaypoint(waypoint); + + // create waypoint marker + const marker = L.marker([waypoint.latitude, longitude], { + icon: L.divIcon({ + className: 'waypoint-label', + iconSize: [26, 26], // increase from 12px to 26px + html: emojiText, + }), + }).bindPopup(tooltip).on('click', function(event) { + // close tooltip on click to prevent tooltip and popup showing at same time + event.target.closeTooltip(); + }); + + // show tooltip on desktop only + if(!isMobile()){ + marker.bindTooltip(tooltip, { + interactive: true, + }); + } + + // add marker to waypoints layer groups + marker.addTo(waypointsLayerGroup); + + // add to cache + waypoints.push(waypoint); + + } + +} + + +function generateConnectionTooltip(connection, nodeA, nodeB, distance) { + let tooltip = `Connection`; + tooltip += `
[${escapeString(nodeA.short_name)}] ${escapeString(nodeA.long_name)} <-> [${escapeString(nodeB.short_name)}] ${escapeString(nodeB.long_name)}`; + tooltip += `
Distance: ${distance}`; + tooltip += `
`; + + // Direction A -> B + if (connection.direction_ab.avg_snr_db != null) { + tooltip += `
${escapeString(nodeA.short_name)} -> ${escapeString(nodeB.short_name)}:`; + tooltip += `
SNR: ${connection.direction_ab.avg_snr_db.toFixed(1)}dB ${getSignalBarsIndicator(connection.direction_ab.avg_snr_db)} (Average of ${connection.direction_ab.total_count} edges)`; + if (connection.direction_ab.last_5_edges.length > 0) { + tooltip += `
Last 5 edges:`; + for (const edge of connection.direction_ab.last_5_edges) { + const timeAgo = moment(new Date(edge.created_at)).fromNow(); + const sourceIcon = edge.source === "TRACEROUTE_APP" ? "⇵" : (edge.source === "NEIGHBORINFO_APP" ? "✳" : "?"); + tooltip += `
   ${edge.snr_db.toFixed(1)}dB ${getSignalBarsIndicator(edge.snr_db)} (${timeAgo} by:${sourceIcon})`; + } + } else { + tooltip += `
No recent edges`; + } + } + + // Direction B -> A + if (connection.direction_ba.avg_snr_db != null) { + tooltip += `

${escapeString(nodeB.short_name)} -> ${escapeString(nodeA.short_name)}:`; + tooltip += `
SNR: ${connection.direction_ba.avg_snr_db.toFixed(1)}dB ${getSignalBarsIndicator(connection.direction_ba.avg_snr_db)} (Average of ${connection.direction_ba.total_count} edges)`; + if (connection.direction_ba.last_5_edges.length > 0) { + tooltip += `
Last 5 edges:`; + for (const edge of connection.direction_ba.last_5_edges) { + const timeAgo = moment(new Date(edge.created_at)).fromNow(); + const sourceIcon = edge.source === "TRACEROUTE_APP" ? "⇵" : (edge.source === "NEIGHBORINFO_APP" ? "✳" : "?"); + tooltip += `
   ${edge.snr_db.toFixed(1)}dB ${getSignalBarsIndicator(edge.snr_db)} (${timeAgo} by:${sourceIcon})`; + } + } else { + tooltip += `
No recent edges`; + } + } + + // Add terrain profile image + const terrainImageUrl = getTerrainProfileImage(nodeA, nodeB); + tooltip += `

Terrain images from HeyWhatsThat.com`; + tooltip += `
`; + + return tooltip; +} + +function onConnectionsUpdated(connections) { + // Clear existing connections + clearAllConnections(); + + for (const connection of connections) { + // Find both node markers + const nodeAMarker = findNodeMarkerById(connection.node_a); + const nodeBMarker = findNodeMarkerById(connection.node_b); + + // Skip if either node marker doesn't exist + if (!nodeAMarker || !nodeBMarker) { + continue; + } + + // Find node objects for names and terrain profile + const nodeA = findNodeById(connection.node_a); + const nodeB = findNodeById(connection.node_b); + + if (!nodeA || !nodeB) { + continue; + } + + // Apply bidirectional filter + const configConnectionsBidirectionalOnly = getConfigConnectionsBidirectionalOnly(); + if(configConnectionsBidirectionalOnly){ + const hasDirectionAB = connection.direction_ab && connection.direction_ab.avg_snr_db != null; + const hasDirectionBA = connection.direction_ba && connection.direction_ba.avg_snr_db != null; + if(!hasDirectionAB || !hasDirectionBA){ + continue; + } + } + + // Apply minimum SNR filter + const configConnectionsMinSnrDb = getConfigConnectionsMinSnrDb(); + if(configConnectionsMinSnrDb != null){ + const snrAB = connection.direction_ab && connection.direction_ab.avg_snr_db != null ? connection.direction_ab.avg_snr_db : null; + const snrBA = connection.direction_ba && connection.direction_ba.avg_snr_db != null ? connection.direction_ba.avg_snr_db : null; + + const configConnectionsBidirectionalMinSnr = getConfigConnectionsBidirectionalMinSnr(); + let hasSnrAboveThreshold; + + if(configConnectionsBidirectionalMinSnr){ + // Bidirectional mode: ALL existing directions must meet threshold + const directionsToCheck = []; + if(snrAB != null) directionsToCheck.push(snrAB); + if(snrBA != null) directionsToCheck.push(snrBA); + + if(directionsToCheck.length === 0){ + // No SNR data in either direction, skip + hasSnrAboveThreshold = false; + } else { + // All existing directions must be above threshold + hasSnrAboveThreshold = directionsToCheck.every(snr => snr > configConnectionsMinSnrDb); + } + } else { + // Default mode: EITHER direction has SNR above threshold + hasSnrAboveThreshold = (snrAB != null && snrAB > configConnectionsMinSnrDb) || (snrBA != null && snrBA > configConnectionsMinSnrDb); + } + + if(!hasSnrAboveThreshold){ + continue; + } + } + + // Calculate distance between nodes + const distanceInMeters = nodeAMarker.getLatLng().distanceTo(nodeBMarker.getLatLng()).toFixed(2); + + // Apply distance filter + const configConnectionsMaxDistanceInMeters = getConfigConnectionsMaxDistanceInMeters(); + if(configConnectionsMaxDistanceInMeters != null && parseFloat(distanceInMeters) > configConnectionsMaxDistanceInMeters){ + continue; + } + + let distance = `${distanceInMeters} meters`; + if (distanceInMeters >= 1000) { + const distanceInKilometers = (distanceInMeters / 1000).toFixed(2); + distance = `${distanceInKilometers} kilometers`; + } + + // Determine line color based on worst average SNR (if colored lines enabled) + const configConnectionsColoredLines = getConfigConnectionsColoredLines(); + const worstSnrDb = connection.worst_avg_snr_db; + const lineColor = configConnectionsColoredLines && worstSnrDb != null ? getColourForSnr(worstSnrDb) : '#2563eb'; + + // Create polyline (bidirectional, no arrows) + const line = L.polyline([ + nodeAMarker.getLatLng(), + nodeBMarker.getLatLng(), + ], { + color: lineColor, + opacity: 0.75, + weight: 3, + }).addTo(connectionsLayerGroup); + + // Generate tooltip + const tooltip = generateConnectionTooltip(connection, nodeA, nodeB, distance); + + // Bind tooltip and popup + line.bindTooltip(tooltip, { + sticky: true, + opacity: 1, + interactive: true, + }) + .bindPopup(tooltip) + .on('click', function(event) { + // close tooltip on click to prevent tooltip and popup showing at same time + event.target.closeTooltip(); + }); + + // If both nodes are backbone nodes, also add to backbone layer group + if (nodeA.is_backbone && nodeB.is_backbone) { + const backboneLine = L.polyline([ + nodeAMarker.getLatLng(), + nodeBMarker.getLatLng(), + ], { + color: lineColor, + opacity: 0.75, + weight: 3, + }).addTo(backboneConnectionsLayerGroup); + + backboneLine.bindTooltip(tooltip, { + sticky: true, + opacity: 1, + interactive: true, + }) + .bindPopup(tooltip) + .on('click', function(event) { + event.target.closeTooltip(); + }); + } + } +} + +function onPositionHistoryUpdated(updatedPositionHistories) { + + let positionHistoryLinesCords = []; + + // add nodes + for(const positionHistory of updatedPositionHistories) { + + // skip position history without position + if(!positionHistory.latitude || !positionHistory.longitude){ + continue; + } + + // find node this position is for + const node = findNodeById(positionHistory.node_id); + if(!node){ + continue; + } + + // fix lat long + positionHistory.latitude = positionHistory.latitude / 10000000; + positionHistory.longitude = positionHistory.longitude / 10000000; + + // skip position history with invalid position + if(!isValidLatLng(positionHistory.latitude, positionHistory.longitude)){ + continue; + } + + // wrap longitude for shortest path, everything to left of australia should be shown on the right + var longitude = parseFloat(positionHistory.longitude); + if(longitude <= 100){ + longitude += 360; + } + + positionHistoryLinesCords.push([positionHistory.latitude, longitude]); + + let tooltip = ""; + if(positionHistory.type === "position"){ + tooltip += `Position`; + } else if(positionHistory.type === "map_report"){ + tooltip += `Map Report`; + } + tooltip += `
[${escapeString(node.short_name)}] ${escapeString(node.long_name)}`; + tooltip += `
${positionHistory.latitude}, ${positionHistory.longitude}`; + tooltip += `
Heard on: ${moment(new Date(positionHistory.created_at)).format("YYYY-MM-DD HH:mm")}`; + + // add gateway info if available + if(positionHistory.gateway_id){ + const gatewayNode = findNodeById(positionHistory.gateway_id); + const gatewayNodeInfo = gatewayNode ? `[${gatewayNode.short_name}] ${gatewayNode.long_name}` : "???"; + tooltip += `
Heard by: ${gatewayNodeInfo}`; + } + + // create position history marker + const marker = L.marker([positionHistory.latitude, longitude],{ + icon: iconPositionHistory, + }).bindTooltip(tooltip).bindPopup(tooltip).on('click', function(event) { + // close tooltip on click to prevent tooltip and popup showing at same time + event.target.closeTooltip(); + }); + + // add marker to position history layer group + marker.addTo(nodePositionHistoryLayerGroup); + + } + + // show lines between position history markers + L.polyline(positionHistoryLinesCords, { + color: "#a855f7", + opacity: 1, + }).addTo(nodePositionHistoryLayerGroup); + +} + +function cleanUpPositionHistory() { + + // close tooltips and popups + closeAllPopups(); + closeAllTooltips(); + + // setup node position history layer + nodePositionHistoryLayerGroup.clearLayers(); + nodePositionHistoryLayerGroup.removeFrom(map); + nodePositionHistoryLayerGroup.addTo(map); + +} + +function setLoading(loading){ + var reloadButton = document.getElementById("reload-button"); + if(loading){ + reloadButton.classList.add("animate-spin"); + } else { + reloadButton.classList.remove("animate-spin"); + } +} + +async function reload(goToNodeId, zoom) { + + // show loading + setLoading(true); + + // clear previous data + clearMap(); + + // fetch nodes + await window.axios.get('/api/v1/nodes').then(async (response) => { + + // update nodes + onNodesUpdated(response.data.nodes); + + // hide loading + setLoading(false); + + // go to node id if provided + if(goToNodeId){ + + // go to node + if(window.goToNode(goToNodeId, false, zoom)){ + return; + } + + // fallback to showing node details since we can't go to the node + window.showNodeDetails(goToNodeId); + + } + + }); + + // fetch waypoints (after awaiting nodes, so we can use nodes cache in waypoint tooltips) + await window.axios.get('/api/v1/waypoints').then(async (response) => { + onWaypointsUpdated(response.data.waypoints); + }); + + // fetch connections (edges) + const connectionsTimePeriodSec = getConfigConnectionsTimePeriodInSeconds(); + const connectionsTimeFrom = connectionsTimePeriodSec ? (Date.now() - connectionsTimePeriodSec * 1000) : undefined; + const connectionsParams = new URLSearchParams(); + if (connectionsTimeFrom) connectionsParams.set('time_from', connectionsTimeFrom); + await window.axios.get(`/api/v1/connections?${connectionsParams.toString()}`).then(async (response) => { + onConnectionsUpdated(response.data.connections ?? []); + }).catch(() => { + onConnectionsUpdated([]); + }); + +} + +function getRegionFrequencyRange(regionName) { + + // determine lora frequency range based on region_name + // https://github.com/meshtastic/firmware/blob/a4c22321fca6fc8da7bab157c3812055603512ba/src/mesh/RadioInterface.cpp#L21 + const regionNameToLoraFrequencyRange = { + "US": "902-928 MHz", + "EU_433": "433-434 MHz", + "EU_868": "869.4-869.65 MHz", + "CN": "470-510 MHz", + "JP": "920.8-927.8 MHz", + "ANZ": "915-928 MHz", + "RU": "868.7-869.2 MHz", + "KR": "920-923 MHz", + "TW": "920-925 MHz", + "IN": "865-867 MHz", + "NZ_865": "864-868 MHz", + "TH": "920-925 MHz", + "UA_433": "433-434.7 MHz", + "UA_868": "868-868.6 MHz", + "MY_433": "433-435 MHz", + "MY_919": "919-924 MHz", + "SG_923": "917-925 MHz", + "LORA_24": "2.4-2.4835 GHz", + "UNSET": "902-928 MHz", + } + + return regionNameToLoraFrequencyRange[regionName] ?? null; + +} + +function getPositionPrecisionInMeters(positionPrecision) { + switch(positionPrecision){ + case 2: return 5976446; + case 3: return 2988223; + case 4: return 1494111; + case 5: return 747055; + case 6: return 373527; + case 7: return 186763; + case 8: return 93381; + case 9: return 46690; + case 10: return 23345; + case 11: return 11672; // Android LOW_PRECISION + case 12: return 5836; + case 13: return 2918; + case 14: return 1459; + case 15: return 729; + case 16: return 364; // Android MED_PRECISION + case 17: return 182; + case 18: return 91; + case 19: return 45; + case 20: return 22; + case 21: return 11; + case 22: return 5; + case 23: return 2; + case 24: return 1; + case 32: return 0; // Android HIGH_PRECISION + } + return null; +} + +function formatPositionPrecision(positionPrecision) { + + // get position precision in meters + const positionPrecisionInMeters = getPositionPrecisionInMeters(positionPrecision); + if(positionPrecisionInMeters == null){ + return "?"; + } + + // format kilometers + if(positionPrecisionInMeters > 1000){ + const positionPrecisionInKilometers = Math.ceil(positionPrecisionInMeters / 1000); + return `±${positionPrecisionInKilometers}km`; + } + + // format meters + return `±${positionPrecisionInMeters}m`; + +} + +function getTooltipContentForNode(node) { + + var loraFrequencyRange = getRegionFrequencyRange(node.region_name); + + var tooltip = `` + + `${escapeString(node.long_name)}` + + `
Short Name: ${escapeString(node.short_name)}` + + (node.num_online_local_nodes != null ? `
Local Nodes Online: ${node.num_online_local_nodes}` : '') + + (node.position_precision != null && node.position_precision !== 32 ? `
Position Precision: ${formatPositionPrecision(node.position_precision)}` : '') + + `

Role: ${node.role_name}` + + `
Hardware: ${node.hardware_model_name}` + + (node.firmware_version != null ? `
Firmware: ${node.firmware_version}` : '') + + `
OK to MQTT: ${node.ok_to_mqtt}`; + + if(node.battery_level){ + if(node.battery_level > 100){ + tooltip += `
Battery: ${node.battery_level > 100 ? 'Plugged In' : node.battery_level}`; + } else { + tooltip += `
Battery: ${node.battery_level}%`; + } + } + + if(node.voltage){ + tooltip += `
Voltage: ${Number(node.voltage).toFixed(2)}V`; + } + + if(node.channel_utilization){ + tooltip += `
Ch Util: ${Number(node.channel_utilization).toFixed(2)}%`; + } + + if(node.air_util_tx){ + tooltip += `
Air Util: ${Number(node.air_util_tx).toFixed(2)}%`; + } + + // ignore alt above 42949000 due to https://github.com/meshtastic/firmware/issues/3109 + if(node.altitude && node.altitude < 42949000){ + tooltip += `
Altitude: ${node.altitude}m`; + } + + // bottom info + tooltip += `

ID: ${node.node_id}`; + tooltip += `
Hex ID: ${node.node_id_hex}`; + tooltip += `
Updated: ${moment(new Date(node.updated_at)).fromNow()}`; + tooltip += (node.mqtt_connection_state_updated_at ? `
MQTT Updated: ${moment(new Date(node.mqtt_connection_state_updated_at)).fromNow()}` : ''); + tooltip += (node.neighbours_updated_at ? `
Neighbours Updated: ${moment(new Date(node.neighbours_updated_at)).fromNow()}` : ''); + tooltip += (node.position_updated_at ? `
Position Updated: ${moment(new Date(node.position_updated_at)).fromNow()}` : ''); + + // show details button + tooltip += `

`; + tooltip += `
`; + tooltip += ``; + + return tooltip; + +} + +function getTooltipContentForWaypoint(waypoint) { + + // get from node name + var fromNode = findNodeById(waypoint.from); + + var tooltip = `${escapeString(waypoint.name)}` + + (waypoint.description ? `
${escapeString(waypoint.description)}` : '') + + `

Expires: ${moment(new Date(waypoint.expire * 1000)).fromNow()}` + + `
Lat/Lng: ${waypoint.latitude}, ${waypoint.longitude}` + + `

From ID: ${waypoint.from}` + + `
From Hex ID: !${Number(waypoint.from).toString(16)}`; + + // show node name this waypoint is from, if possible + if(fromNode != null){ + tooltip += `
From Node: ${escapeString(fromNode.long_name) || 'Unnamed Node'}`; + } else { + tooltip += `
From Node: ???`; + } + + // bottom info + tooltip += `

ID: ${waypoint.waypoint_id}`; + tooltip += `
Updated: ${moment(new Date(waypoint.updated_at)).fromNow()}`; + + return tooltip; + +} + +window._onHideNodeConnectionsClick = function() { + cleanUpNodeConnections(); +}; + +// parse url params +var queryParams = new URLSearchParams(location.search); +var queryNodeId = queryParams.get('node_id'); +var queryLat = queryParams.get('lat'); +var queryLng = queryParams.get('lng'); +var queryZoom = queryParams.get('zoom'); + +// go to lat/lng if provided +if(queryLat && queryLng){ + const zoomLevel = queryZoom || getConfigZoomLevelGoToNode(); + map.flyTo([queryLat, queryLng], zoomLevel, { + animate: false, + }); +} + +// auto update url when lat/lng/zoom changes +map.on("moveend zoomend", function() { + + // check if user enabled auto updating position in url + const autoUpdatePositionInUrl = getConfigAutoUpdatePositionInUrl(); + if(!autoUpdatePositionInUrl){ + return; + } + + // get map info + const latLng = map.getCenter(); + const zoom = map.getZoom(); + + // construct new url + const url = new URL(window.location.href); + url.searchParams.set("lat", latLng.lat); + url.searchParams.set("lng", latLng.lng); + url.searchParams.set("zoom", zoom); + + // update current url + if(window.history.replaceState){ + window.history.replaceState(null, null, url.toString()); + } + +}); + +// reload and go to provided node id +reload(queryNodeId, queryZoom); + +// WebSocket connection for real-time messages +var ws = null; +var tracerouteCooldown = {}; // Track last traceroute time per from node (for 20s cooldown) +var activeTracerouteKeys = new Set(); // Track active traceroute visualizations to prevent duplicates +var tracerouteLines = {}; // Track lines for each traceroute route key for cleanup + +function connectWebSocket() { + // Determine WebSocket URL - use same hostname as current page, port 8081 + const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + // Heuristic: if running on localhost, use port 8081; otherwise use /ws path via Nginx + const isLocalhost = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; + const wsUrl = isLocalhost + ? `${wsProtocol}//${location.hostname}:8081` + : `${wsProtocol}//${location.host}/ws`; + + console.log('Connecting to WebSocket:', wsUrl); + ws = new WebSocket(wsUrl); + + ws.onopen = function() { + console.log('WebSocket connected'); + }; + + ws.onmessage = function(event) { + try { + const message = JSON.parse(event.data); + handleWebSocketMessage(message); + } catch (e) { + console.error('Error parsing WebSocket message:', e); + } + }; + + ws.onerror = function(error) { + console.error('WebSocket error:', error); + }; + + ws.onclose = function() { + console.log('WebSocket disconnected, reconnecting in 5 seconds...'); + setTimeout(connectWebSocket, 5000); + }; +} + +function handleWebSocketMessage(message) { + if (message.type === 'traceroute') { + handleTraceroute(message.data); + } +} + +function handleTraceroute(data) { + // Only visualize traceroutes where want_response is false (the reply coming back) + if (data.want_response) { + return; + } + + // When want_response is false, from and to are swapped from the original request + // The path goes from 'to' (original sender) through route to 'from' (original destination) + const originalSender = data.to; // This was the original sender + const originalDestination = data.from; // This was the original destination + const route = data.route || []; + const snrTowards = data.snr_towards || []; + + // Deduplicate: ignore traceroutes from the same original sender for 20 seconds + const now = Date.now(); + if (tracerouteCooldown[originalSender] && (now - tracerouteCooldown[originalSender]) < 20000) { + return; // Still in cooldown period + } + + // Create unique key for this traceroute path to prevent duplicate visualizations + // Use original sender (to), original destination (from), and route to create unique key + // (ignoring gateway_id since multiple gateways can receive same route) + const routeKey = `${originalSender}-${originalDestination}-${route.join('-')}`; + if (activeTracerouteKeys.has(routeKey)) { + return; // Already visualizing this route + } + + // Mark as active and set cooldown + activeTracerouteKeys.add(routeKey); + tracerouteCooldown[originalSender] = now; + + // Build the complete path: to (original sender) -> route[0] -> route[1] -> ... -> from (original destination) + const path = [originalSender]; // Start from original sender + if (route.length > 0) { + path.push(...route); + } + path.push(originalDestination); // End at original destination + + // Visualize the traceroute with animated hops + visualizeTraceroute(path, snrTowards, routeKey); +} + +function visualizeTraceroute(path, snrTowards, routeKey) { + // Verify all nodes in path exist on map + const pathMarkers = []; + for (const nodeId of path) { + const marker = findNodeMarkerById(nodeId); + if (!marker) { + // Node not on map, skip this traceroute + activeTracerouteKeys.delete(routeKey); + return; + } + pathMarkers.push(marker); + } + + // Store lines and overlays for this route key for cleanup + const routeElements = { + lines: [], + startOverlay: null, + endOverlay: null, + }; + tracerouteLines[routeKey] = routeElements; + + // Color starting node (first in path) green and destination node (last in path) red + const startMarker = pathMarkers[0]; + const endMarker = pathMarkers[pathMarkers.length - 1]; + + const startOverlay = L.marker(startMarker.getLatLng(), { + icon: iconTracerouteStart, + zIndexOffset: 10000, // Ensure it's on top + }).addTo(traceroutesLayerGroup); + + const endOverlay = L.marker(endMarker.getLatLng(), { + icon: iconTracerouteEnd, + zIndexOffset: 10000, // Ensure it's on top + }).addTo(traceroutesLayerGroup); + + // Store overlays for cleanup + routeElements.startOverlay = startOverlay; + routeElements.endOverlay = endOverlay; + + // Animate each hop sequentially + let hopIndex = 0; + const animateNextHop = () => { + if (hopIndex >= pathMarkers.length - 1) { + // All hops animated, cleanup after delay + setTimeout(() => { + if (tracerouteLines[routeKey]) { + const routeElements = tracerouteLines[routeKey]; + // Remove all lines + if (routeElements.lines) { + routeElements.lines.forEach(line => { + line.remove(); + }); + } + // Remove node overlays + if (routeElements.startOverlay) { + routeElements.startOverlay.remove(); + } + if (routeElements.endOverlay) { + routeElements.endOverlay.remove(); + } + delete tracerouteLines[routeKey]; + } + activeTracerouteKeys.delete(routeKey); + }, 2500); + return; + } + + const fromMarker = pathMarkers[hopIndex]; + const toMarker = pathMarkers[hopIndex + 1]; + const snr = hopIndex < snrTowards.length ? snrTowards[hopIndex] : null; + + // Use orange color for all traceroute lines + const lineColor = '#f97316'; // orange + + // Create animated polyline for this hop with orange dotted style + const line = L.polyline([fromMarker.getLatLng(), toMarker.getLatLng()], { + color: lineColor, + weight: 4, + opacity: 0, // Start invisible + // dashArray: '10, 5', // Dotted line style + zIndexOffset: 10000, + }).addTo(traceroutesLayerGroup); + + // Fade in animation + line.setStyle({ opacity: 1.0 }); + tracerouteLines[routeKey].lines.push(line); + + // Animate next hop after 700ms delay + hopIndex++; + setTimeout(animateNextHop, 700); + }; + + // Start animation + animateNextHop(); +} + +// Connect WebSocket when page loads +connectWebSocket(); \ No newline at end of file diff --git a/src/public/images/devices/HELTEC_MESH_POCKET.png b/src/public/images/devices/HELTEC_MESH_POCKET.png new file mode 100644 index 0000000..ae7a797 Binary files /dev/null and b/src/public/images/devices/HELTEC_MESH_POCKET.png differ diff --git a/src/public/images/devices/HELTEC_MESH_SOLAR.png b/src/public/images/devices/HELTEC_MESH_SOLAR.png new file mode 100644 index 0000000..a6575ef Binary files /dev/null and b/src/public/images/devices/HELTEC_MESH_SOLAR.png differ diff --git a/src/public/images/devices/HELTEC_V2_0.png b/src/public/images/devices/HELTEC_V2_0.png old mode 100755 new mode 100644 index bbdab59..6dd4c49 Binary files a/src/public/images/devices/HELTEC_V2_0.png and b/src/public/images/devices/HELTEC_V2_0.png differ diff --git a/src/public/images/devices/HELTEC_V2_1.png b/src/public/images/devices/HELTEC_V2_1.png old mode 100755 new mode 100644 index 6735a1b..6dd4c49 Binary files a/src/public/images/devices/HELTEC_V2_1.png and b/src/public/images/devices/HELTEC_V2_1.png differ diff --git a/src/public/images/devices/HELTEC_V3.png b/src/public/images/devices/HELTEC_V3.png old mode 100755 new mode 100644 index 2c83862..6dd4c49 Binary files a/src/public/images/devices/HELTEC_V3.png and b/src/public/images/devices/HELTEC_V3.png differ diff --git a/src/public/images/devices/HELTEC_V4.png b/src/public/images/devices/HELTEC_V4.png new file mode 100644 index 0000000..6dd4c49 Binary files /dev/null and b/src/public/images/devices/HELTEC_V4.png differ diff --git a/src/public/images/devices/HELTEC_VISION_MASTER_E213.png b/src/public/images/devices/HELTEC_VISION_MASTER_E213.png new file mode 100644 index 0000000..5000861 Binary files /dev/null and b/src/public/images/devices/HELTEC_VISION_MASTER_E213.png differ diff --git a/src/public/images/devices/LILYGO_TBEAM_S3_CORE.png b/src/public/images/devices/LILYGO_TBEAM_S3_CORE.png old mode 100755 new mode 100644 index 82a05f6..c763601 Binary files a/src/public/images/devices/LILYGO_TBEAM_S3_CORE.png and b/src/public/images/devices/LILYGO_TBEAM_S3_CORE.png differ diff --git a/src/public/images/devices/NRF52_PROMICRO_DIY.png b/src/public/images/devices/NRF52_PROMICRO_DIY.png new file mode 100644 index 0000000..3ece7f1 Binary files /dev/null and b/src/public/images/devices/NRF52_PROMICRO_DIY.png differ diff --git a/src/public/images/devices/PORTDUINO.png b/src/public/images/devices/PORTDUINO.png new file mode 100644 index 0000000..0ccea0d Binary files /dev/null and b/src/public/images/devices/PORTDUINO.png differ diff --git a/src/public/images/devices/RP2040_LORA.png b/src/public/images/devices/RP2040_LORA.png old mode 100755 new mode 100644 index aacbe84..e83fa3a Binary files a/src/public/images/devices/RP2040_LORA.png and b/src/public/images/devices/RP2040_LORA.png differ diff --git a/src/public/images/devices/RPI_PICO.png b/src/public/images/devices/RPI_PICO.png old mode 100755 new mode 100644 index 4e25730..ed0ad1c Binary files a/src/public/images/devices/RPI_PICO.png and b/src/public/images/devices/RPI_PICO.png differ diff --git a/src/public/images/devices/SEEED_SOLAR_NODE.png b/src/public/images/devices/SEEED_SOLAR_NODE.png new file mode 100644 index 0000000..7f894bc Binary files /dev/null and b/src/public/images/devices/SEEED_SOLAR_NODE.png differ diff --git a/src/public/images/devices/SEEED_WIO_TRACKER_L1.png b/src/public/images/devices/SEEED_WIO_TRACKER_L1.png new file mode 100644 index 0000000..e432076 Binary files /dev/null and b/src/public/images/devices/SEEED_WIO_TRACKER_L1.png differ diff --git a/src/public/images/devices/SEEED_XIAO_S3.png b/src/public/images/devices/SEEED_XIAO_S3.png new file mode 100644 index 0000000..cceedfd Binary files /dev/null and b/src/public/images/devices/SEEED_XIAO_S3.png differ diff --git a/src/public/images/devices/STATION_G2.png b/src/public/images/devices/STATION_G2.png new file mode 100644 index 0000000..290f5eb Binary files /dev/null and b/src/public/images/devices/STATION_G2.png differ diff --git a/src/public/images/devices/TBEAM.png b/src/public/images/devices/TBEAM.png old mode 100755 new mode 100644 index 07e1ea9..0968f5b Binary files a/src/public/images/devices/TBEAM.png and b/src/public/images/devices/TBEAM.png differ diff --git a/src/public/images/devices/THINKNODE_M1.png b/src/public/images/devices/THINKNODE_M1.png new file mode 100644 index 0000000..7995026 Binary files /dev/null and b/src/public/images/devices/THINKNODE_M1.png differ diff --git a/src/public/images/devices/TLORA_T3_S3.png b/src/public/images/devices/TLORA_T3_S3.png index ab9a716..f241e32 100644 Binary files a/src/public/images/devices/TLORA_T3_S3.png and b/src/public/images/devices/TLORA_T3_S3.png differ diff --git a/src/public/images/devices/TLORA_V2_1_1P6.png b/src/public/images/devices/TLORA_V2_1_1P6.png old mode 100755 new mode 100644 index a85f673..9e50235 Binary files a/src/public/images/devices/TLORA_V2_1_1P6.png and b/src/public/images/devices/TLORA_V2_1_1P6.png differ diff --git a/src/public/images/devices/T_DECK.png b/src/public/images/devices/T_DECK.png old mode 100755 new mode 100644 index 1d3f495..89ae6e3 Binary files a/src/public/images/devices/T_DECK.png and b/src/public/images/devices/T_DECK.png differ diff --git a/src/public/images/devices/T_ECHO.png b/src/public/images/devices/T_ECHO.png old mode 100755 new mode 100644 index 076c748..baa3fc5 Binary files a/src/public/images/devices/T_ECHO.png and b/src/public/images/devices/T_ECHO.png differ diff --git a/src/public/images/devices/T_ETH_ELITE.png b/src/public/images/devices/T_ETH_ELITE.png new file mode 100644 index 0000000..3a25fbc Binary files /dev/null and b/src/public/images/devices/T_ETH_ELITE.png differ diff --git a/src/public/images/devices/XIAO_NRF52_KIT.png b/src/public/images/devices/XIAO_NRF52_KIT.png new file mode 100644 index 0000000..f3cc2eb Binary files /dev/null and b/src/public/images/devices/XIAO_NRF52_KIT.png differ diff --git a/src/public/index.html b/src/public/index.html index 92ce175..ff76890 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -3,15 +3,15 @@ - Meshtastic Map - + DL4AX Meshtastic Map + - - + + @@ -48,95 +48,8 @@ - + + @@ -145,32 +58,8 @@
- -
- - -
-
Service Announcement
-
- Changes were made to mqtt.meshtastic.org. Uplink your nodes to to continue showing on this map. -
-
- - - - -
- -
+
@@ -184,16 +73,8 @@
- - - -
-
Meshtastic Map
-
- Created by Liam Cottle -
+
+
@@ -231,16 +112,6 @@ - -
- - - -
-
- - - -
-
-
-
- - - - - -
- - -
- -

Meshtastic Map

-

Created by Liam Cottle

- -
- - -
- 👋 Welcome to my open source map of Meshtastic nodes heard on MQTT. -
- - -
-
Features
-
-
    -
  • The map shows nodes that have sent a valid position to MQTT.
  • -
  • Position packets must be unencrypted, or encrypted with the default key.
  • -
  • Use the search bar to find nodes by ID or name.
  • -
  • Hover over nodes (on desktop) to see basic details.
  • -
  • Click a node to see info such as telemetry graphs and traceroutes.
  • -
  • Use the top right layers panel to show neighbours and waypoints.
  • -
  • Use the settings button to configure the map to your liking.
  • -
  • Have a feature request, or found a bug? Open an issue on GitHub.
  • -
-
-
- - -
-
FAQ
-
-
-
How do I add my node to the map?
-
Your node, or a node that hears your node must uplink to our MQTT server.
-
Your position packet must be unencrypted, or encrypted with the default key.
-
If your node has v2.5 firmware or newer, you must enable "OK to MQTT".
-
Use the MQTT server details below to uplink to this map.
-
-
-
What MQTT server should I use?
-
    -
  • Address: mqtt.meshtastic.liamcottle.net
  • -
  • Username: uplink
  • -
  • Password: uplink
  • -
  • Encryption Enabled: Yes
  • -
  • JSON Output: No
  • -
  • TLS Enabled: No
  • -
-
Please note, nodes can only uplink to this server. Downlink is disabled.
-
We suggest running dedicated nodes for uplinking to the map.
-
-
-
How do I remove my node from the map?
-
Nodes that have not been heard for 7 days are automatically removed.
-
Disable position reporting in your node to prevent it coming back.
-
Use custom encryption keys so the public can't see your position data.
-
If your node has v2.5 firmware or newer, we ignore packets if "OK to MQTT" is disabled.
-
To have your node removed now, please contact me.
-
-
-
How do I see neighbours a node heard?
-
Open the top right layers panel and enable neighbours.
-
Some neighbours are from MQTT, this is patched in latest firmware.
-
-
-
Why is my node showing up in the wrong place?
-
This public map obfuscates your position packets for v2.4 firmware and older.
-
Nodes on v2.4 and older have their positions obfuscated to 2 decimal places.
-
Nodes on v2.5 and newer, with "OK to MQTT" enabled, will show positions with your configured precision.
-
Nodes on v2.5 and newer, with "OK to MQTT" disabled, will not update their positions.
-
-
-
- - -
-
Legal
-
-
This project is not affiliated with or endorsed by the Meshtastic project.
-
The Meshtastic logo is the trademark of Meshtastic LLC.
-
Map tiles provided by OpenStreetMap
-
-
- - - - -
- -
-
-
-
- - -
- - -
-
LoRa Config
-
    - - -
  • -
    Region
    -
    - {{ selectedNode.region_name }} ({{ getRegionFrequencyRange(selectedNode.region_name) }}) - ??? -
    -
  • - - -
  • -
    Modem Preset
    -
    - {{ selectedNode.modem_preset_name }} - ??? -
    -
  • - - -
  • -
    Has Default Channel
    -
    - {{ selectedNode.has_default_channel ? "Yes" : "No" }} - ??? -
    -
  • - -
-
-
@@ -805,6 +442,7 @@ +
@@ -895,6 +533,7 @@ +
@@ -919,6 +558,10 @@
Pressure
+
+
+
IAQ
+
@@ -964,6 +607,7 @@ + @@ -1402,29 +1046,6 @@ - -
- -
Nodes that have not uplinked to MQTT in this time will show as blue icons. Reload to update map.
- -
-
@@ -1471,11 +1092,66 @@
- +
- -
Neighbours further than this are hidden. Reload to update map.
- + +
Edges from traceroutes and neighbour info within this time period are shown in the Connections layer. Reload to update map.
+ +
+ + +
+
+
+ +
+ +
+
Colors the connection lines by the average SNR in the worst direction. Reload to update map.
+
+ + +
+
+
+ +
+ +
+
Only show connections where data flows in both directions. Reload to update map.
+
+ + +
+ +
Only show connections where at least one direction has SNR above this threshold. Leave empty to show all connections. Reload to update map.
+ +
+
+ +
+ +
+
If checked, all existing directions must meet the minimum SNR threshold (both directions if bidirectional, single direction if unidirectional).
+
+ + +
+ +
Connections further than this are hidden. Reload to update map.
+
@@ -1490,8 +1166,8 @@
Metrics will be shown in the selected format.
@@ -1516,7 +1192,6 @@
Map will animate flying to nodes.
- @@ -1526,7 +1201,7 @@ - +