diff --git a/.env-sample b/.env-sample index 1b44b63e..64b12a5a 100644 --- a/.env-sample +++ b/.env-sample @@ -42,6 +42,13 @@ LND_GRPC_HOST='localhost:10009' REDIS_URL='redis://localhost:6379/1' +# If set to True, load to console (default is False) +# LOG_TO_CONSOLE=True +# If set, log to file specified (LOG_TO_CONSOLE should be False) +# LOG_FILE="" +# Change logger level (default is "WARNING") +# LOGGER_LEVEL="WARNING" + # List of market price public APIs. If the currency is available in more than 1 API, will use median price. MARKET_PRICE_APIS = https://blockchain.info/ticker, https://api.yadio.io/exrates/BTC, https://bitpay.com/rates/BTC, https://criptoya.com/api/btc diff --git a/.gitignore b/.gitignore index 01e3d2d3..f57dee36 100755 --- a/.gitignore +++ b/.gitignore @@ -661,3 +661,6 @@ nodeapp/*.html # Protocol Buffers api/lightning/*.proto + +# Traditional environment +/traditional/ diff --git a/api/logics.py b/api/logics.py index d518415a..1fec0ccc 100644 --- a/api/logics.py +++ b/api/logics.py @@ -1327,7 +1327,7 @@ class Logics: print(str(e)) if "failed to connect to all addresses" in str(e): return False, { - "bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware." + "bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware." } elif "wallet locked" in str(e): return False, { @@ -1472,7 +1472,7 @@ class Logics: except Exception as e: if "status = StatusCode.UNAVAILABLE" in str(e): return False, { - "bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware." + "bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware." } take_order.taker_bond = LNPayment.objects.create( @@ -1572,7 +1572,7 @@ class Logics: except Exception as e: if "status = StatusCode.UNAVAILABLE" in str(e): return False, { - "bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware." + "bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware." } order.trade_escrow = LNPayment.objects.create( diff --git a/api/nostr.py b/api/nostr.py index 54c9ceb4..a471be2b 100644 --- a/api/nostr.py +++ b/api/nostr.py @@ -27,7 +27,8 @@ class Nostr: # Add relays and connect await client.add_relay("ws://localhost:7777") - await client.add_relay("ws://localhost:7778") + strfry_port = config("STRFRY_PORT", cast=str, default="7778") + await client.add_relay(f"ws://localhost:{strfry_port}") await client.connect() robot_name = await self.get_robot_name(order) diff --git a/api/oas_schemas.py b/api/oas_schemas.py index 2d28b916..19af089d 100644 --- a/api/oas_schemas.py +++ b/api/oas_schemas.py @@ -191,7 +191,7 @@ class OrderViewSchema: OpenApiExample( "When Robosats node is down", value={ - "bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware." + "bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware." }, status_codes=[400], ), @@ -539,7 +539,7 @@ class InfoViewSchema: - 24h volume - all time volume - Node info - - lnd version + - node version - node id - node alias - network diff --git a/api/utils.py b/api/utils.py index 83dfb25d..e74107e1 100644 --- a/api/utils.py +++ b/api/utils.py @@ -385,7 +385,7 @@ def compute_avg_premium(queryset): def validate_pgp_keys(pub_key, enc_priv_key): """Validates PGP valid keys. Formats them in a way understandable by the frontend""" - gpg = gnupg.GPG() + gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None)) # Standardize format with linux linebreaks '\n'. Windows users submitting their own keys have '\r\n' breaking communication. enc_priv_key = enc_priv_key.replace("\r\n", "\n").replace("\\", "\n") @@ -439,7 +439,7 @@ def verify_signed_message(pub_key, signed_message): Verifies a signed cleartext PGP message. Returns whether the signature is valid (was made by the given pub_key) and the content of the message. """ - gpg = gnupg.GPG() + gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None)) # import the public key import_result = gpg.import_keys(pub_key) diff --git a/api/views.py b/api/views.py index 31ffe73f..069303d1 100644 --- a/api/views.py +++ b/api/views.py @@ -16,6 +16,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from api.logics import Logics +from api.tasks import cache_market from api.models import ( Currency, LNPayment, @@ -150,6 +151,9 @@ class MakerView(CreateAPIView): status.HTTP_400_BAD_REQUEST, ) + if len(Currency.objects.all()) == 0: + cache_market() + # Creates a new order order = Order( type=type, diff --git a/docs/_pages/docs/pt/contribute/01-development.md b/docs/_pages/docs/pt/contribute/01-development.md index 90769565..b2506a22 100644 --- a/docs/_pages/docs/pt/contribute/01-development.md +++ b/docs/_pages/docs/pt/contribute/01-development.md @@ -20,7 +20,7 @@ _!!! Cuidado com golpistas que se passam por administradores do RoboSats. Os adm - **Simplex:** [Grupo Principal do RoboSats](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FyEX_vdhWew_FkovCQC3mRYRWZB1j_cBq%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAnrf9Jw3Ajdp4EQw71kqA64VgsIIzw8YNn68WjF09jFY%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22hWnMVPnJl-KT3-virDk0JA%3D%3D%22%7D). Tem perguntas ou um problema? Encontre suporte comunitário na conversa pública do grupo SimpleX. Se você quer se juntar a outros robôs legais e aprender mais sobre o RoboSats, então essas discussões acontecem no SimpleX, Nostr e nos grupos de chat Matrix. -- **Nostr:** [Grupo Geral do RoboSats](https://snort.social/e/note1tfwvglg8xz8420pfgav0dc9mqekv02nkpck2axefklrema7lk6wszmwxdy). Junte-se a outros robôs legais e não hesite em fazer perguntas sobre o RoboSats! Além disso, a conta [RoboSats Nostr](npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82) fornece atualizações importantes do projeto, dicas e truques de uso do RoboSats, e outros comentários centrados na privacidade. Perguntas e interações são bem-vindas. Lembre-se: problemas que exigem suporte da equipe do RoboSats devem ser direcionados para o grupo principal do SimpleX, onde as respostas são mais rápidas e a equipe pode investigar mais a fundo o seu problema. +- **Nostr:** [Grupo Geral do RoboSats](https://snort.social/e/note1tfwvglg8xz8420pfgav0dc9mqekv02nkpck2axefklrema7lk6wszmwxdy). Junte-se a outros robôs legais e não hesite em fazer perguntas sobre o RoboSats! Além disso, a conta [RoboSats Nostr](nprofile1qqsyx53h3h7ec4fwlspjq0kqec5gv54t7rc48xdtq6q4y94wsw4fnjqsg3jtv) fornece atualizações importantes do projeto, dicas e truques de uso do RoboSats, e outros comentários centrados na privacidade. Perguntas e interações são bem-vindas. Lembre-se: problemas que exigem suporte da equipe do RoboSats devem ser direcionados para o grupo principal do SimpleX, onde as respostas são mais rápidas e a equipe pode investigar mais a fundo o seu problema. - **Matrix:** [Grupo de Desenvolvimento do RoboSats](https://matrix.to/#/#robosats:matrix.org). Grupo de chat principal de comunicação entre desenvolvedores, onde discussões abertas e técnicas sobre o desenvolvimento ocorrem. Discussões sobre mudanças de código acontecem em issues e pull requests (PRs) do GitHub. diff --git a/docs/assets/schemas/api-latest.yaml b/docs/assets/schemas/api-latest.yaml index 0501c3fa..f1515d75 100644 --- a/docs/assets/schemas/api-latest.yaml +++ b/docs/assets/schemas/api-latest.yaml @@ -162,7 +162,7 @@ paths: - 24h volume - all time volume - Node info - - lnd version + - node version - node id - node alias - network @@ -419,7 +419,7 @@ paths: summary: When maker bond expires (as maker) WhenRobosatsNodeIsDown: value: - bad_request: The Lightning Network Daemon (LND) is down. Write + bad_request: The lightning node is down. Write in the Telegram group to make sure the staff is aware. summary: When Robosats node is down description: '' diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2de1f0a9..9e3f4403 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,7 +10,6 @@ "license": "ISC", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", - "@christopherpickering/react-leaflet-markercluster": "^1.1.0", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@mui/base": "^5.0.0-beta.70", @@ -18,34 +17,35 @@ "@mui/lab": "^7.0.0-beta.12", "@mui/material": "^7.1.0", "@mui/system": "^7.1.0", - "@mui/x-data-grid": "^8.3.1", - "@mui/x-date-pickers": "^8.3.0", - "@nivo/core": "^0.96.0", - "@nivo/line": "^0.96.0", + "@mui/x-data-grid": "^8.4.0", + "@mui/x-date-pickers": "^8.4.0", + "@nivo/core": "^0.99.0", + "@nivo/line": "^0.99.0", "base-ex": "^0.8.1", "country-flag-icons": "^1.5.19", "date-fns": "^4.1.0", "file-replace-loader": "^1.4.2", - "i18next": "^25.1.2", + "i18next": "^25.2.1", "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", "install": "^0.13.0", - "js-sha256": "^0.11.0", + "js-sha256": "^0.11.1", "latlon-geohash": "^2.0.0", "leaflet": "^1.9.4", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.13.0", - "npm": "^11.3.0", + "npm": "^11.4.1", "openpgp": "^5.11.0", - "react": "^18.3.0", + "react": "^19.1.0", "react-countdown": "^2.3.6", - "react-dom": "^18.3.0", + "react-dom": "^19.1.0", "react-grid-layout": "^1.5.1", - "react-i18next": "^15.5.1", + "react-i18next": "^15.5.2", "react-image": "^4.1.0", - "react-leaflet": "^4.2.1", + "react-leaflet": "^5.0.0", + "react-leaflet-markercluster": "^5.0.0-rc.0", "react-qr-code": "^2.0.15", - "react-router-dom": "^7.6.0", + "react-router-dom": "^7.6.1", "react-smooth-image": "^1.1.0", "react-world-flags": "^1.6.0", "reconnecting-websocket": "^4.4.0", @@ -55,29 +55,29 @@ "websocket": "^1.0.35" }, "devDependencies": { - "@babel/core": "^7.27.1", - "@babel/plugin-transform-runtime": "^7.27.1", + "@babel/core": "^7.27.3", + "@babel/plugin-transform-runtime": "^7.27.3", "@babel/preset-env": "^7.27.2", "@babel/preset-react": "^7.27.1", "@babel/preset-typescript": "^7.27.1", - "@babel/runtime": "^7.27.1", + "@babel/runtime": "^7.27.3", "@eslint/compat": "^1.2.9", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.26.0", + "@eslint/js": "^9.27.0", "@types/jest": "^29.5.14", "@types/latlon-geohash": "^2.0.4", - "@types/leaflet": "^1.9.17", - "@types/react": "^19.1.3", - "@types/react-dom": "^19.1.3", + "@types/leaflet": "^1.9.18", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.5", "@types/webpack": "^5.28.5", - "@typescript-eslint/eslint-plugin": "^8.32.0", - "@typescript-eslint/parser": "^8.32.0", + "@typescript-eslint/eslint-plugin": "^8.33.0", + "@typescript-eslint/parser": "^8.33.0", "babel-loader": "^10.0.0", "css-loader": "^7.1.2", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "eslint-config-love": "^120.0.0", "eslint-config-prettier": "^10.1.5", - "eslint-import-resolver-typescript": "^4.3.4", + "eslint-import-resolver-typescript": "^4.4.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-n": "^17.18.0", "eslint-plugin-prettier": "^5.4.0", @@ -85,14 +85,14 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "filemanager-webpack-plugin": "^8.0.0", - "globals": "^16.1.0", + "globals": "^16.2.0", "html-webpack-plugin": "^5.6.3", "jest": "^29.7.0", "prettier": "^3.5.3", "style-loader": "^4.0.0", "ts-node": "^10.9.2", "typescript": "^5.8.3", - "webpack": "^5.99.8", + "webpack": "^5.99.9", "webpack-cli": "^6.0.1" } }, @@ -124,30 +124,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", - "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz", + "integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", - "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.3.tgz", + "integrity": "sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helpers": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.3", + "@babel/parser": "^7.27.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.3", + "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -163,13 +163,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", - "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz", + "integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/parser": "^7.27.3", + "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -179,12 +179,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", - "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -289,14 +289,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", - "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -417,25 +417,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.3.tgz", + "integrity": "sha512-h/eKy9agOya1IGuLaZ9tEUgz+uIRXcbtOhRtUyyMf8JFmn1iT13vnl/IGVWSkdOCG/pC57U4S1jnAabAavTMwg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", - "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.3.tgz", + "integrity": "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -899,9 +899,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", - "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.3.tgz", + "integrity": "sha512-+F8CnfhuLhwUACIJMLWnjz6zvzYM2r0yeIHKlbgfw7ml8rOMJsXNXV/hyRcb3nb493gRs4WvYpQAndWj/qQmkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -997,9 +997,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", - "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz", + "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==", "dev": true, "license": "MIT", "dependencies": { @@ -1345,15 +1345,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", - "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.3.tgz", + "integrity": "sha512-7ZZtznF9g4l2JCImCo5LNKFHB5eXnN39lLtLY5Tg+VkR0jwOt7TBciMckuiQIOIW7L5tkQOCh3bVGYeXgMx52Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.3", "@babel/plugin-transform-parameters": "^7.27.1" }, "engines": { @@ -1599,9 +1599,9 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", - "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.3.tgz", + "integrity": "sha512-bA9ZL5PW90YwNgGfjg6U+7Qh/k3zCEQJ06BFgAGRp/yMjw9hP9UGbGPtx3KSOkHGljEPCCxaE+PH4fUR2h1sDw==", "dev": true, "license": "MIT", "dependencies": { @@ -1928,9 +1928,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz", + "integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1951,16 +1951,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", - "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.3.tgz", + "integrity": "sha512-lId/IfN/Ye1CIu8xG7oKBHXd2iNb2aW1ilPszzGcJug6M8RCKfVNcYhpI5+bMvFYjK7lXIM0R+a+6r8xhHp2FQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1978,9 +1978,9 @@ } }, "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1997,24 +1997,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@christopherpickering/react-leaflet-markercluster": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@christopherpickering/react-leaflet-markercluster/-/react-leaflet-markercluster-1.1.0.tgz", - "integrity": "sha512-69Q3c/Szq7vXNSq6wy+wi6Wj4yHHVxzAuJMiFMgTcoyuZO4EQj8a6qzOc/XdcuQbNX+gfFe2Me/C61bc6sjO4g==", - "license": "MIT", - "dependencies": { - "@react-leaflet/core": "^2.1.0", - "leaflet": "^1.9.3", - "leaflet.markercluster": "^1.5.3", - "postcss-flexbugs-fixes": "^5.0.2", - "react-leaflet": "^4.0.0" - }, - "peerDependencies": { - "leaflet": "^1.9.3", - "leaflet.markercluster": "^1.5.3", - "react-leaflet": "^4.0.0" - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -2308,9 +2290,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2358,13 +2340,16 @@ } }, "node_modules/@eslint/js": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", - "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -2378,13 +2363,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" }, "engines": { @@ -2963,28 +2948,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz", - "integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.3", - "eventsource": "^3.0.2", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@mui/base": { "version": "5.0.0-beta.70", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.70.tgz", @@ -3481,14 +3444,14 @@ } }, "node_modules/@mui/x-data-grid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.3.1.tgz", - "integrity": "sha512-mSo2g0ZZzasDQ4kKrFdJVk7dJgz77jF/e8udvGqnnTgnQXlqLMpKne/veL3gRdi3TJxxTv2vqXtX7IZfWGJecQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.4.0.tgz", + "integrity": "sha512-c0fgMhvQTjCSo3LgRK1Mdk2msktCl9uwMYUYlP6bbqJ7I03IvS+1aZ+s3nSLmaq1aVh7sE2Bnuz63OnVerTLJA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1", "@mui/utils": "^7.0.2", - "@mui/x-internals": "8.3.1", + "@mui/x-internals": "8.4.0", "clsx": "^2.1.1", "prop-types": "^15.8.1", "reselect": "^5.1.1", @@ -3565,35 +3528,15 @@ } } }, - "node_modules/@mui/x-data-grid/node_modules/@mui/x-internals": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.3.1.tgz", - "integrity": "sha512-8kIxT66cea63iEseEIHSWzKju2Wzl7MsWFoAUQEyRvYqOFa2j9Un2Vn/EH2vy9nm/MtMAYpwOE/nt68/KTIA2w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.27.1", - "@mui/utils": "^7.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@mui/x-date-pickers": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.3.0.tgz", - "integrity": "sha512-N4Rw/Q6bAHBj7BpLEGE84MG05B56wWQStZch9NqA0U8vTt9TGvkj27fQaboOIikk6ERQTHM2mMoLZgwQAvlhIw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.4.0.tgz", + "integrity": "sha512-x7jI7JnKK25xL3yjD2Z1r86gAWtabKj9ogI2WDKd/v9WwE1VxmDD/NTiXprEZFo9psPOoqr+juPGDz5Cb2v7jw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1", "@mui/utils": "^7.0.2", - "@mui/x-internals": "8.3.0", + "@mui/x-internals": "8.4.0", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -3699,9 +3642,9 @@ } }, "node_modules/@mui/x-internals": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.3.0.tgz", - "integrity": "sha512-wSVxg5aSO9xvJT7oarhsXqr03NeP355Whm7Qn6z3VvxdGwNc7K7vKpez3E+2KMxtdvywOmragwlSdTaO1K6qkg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.4.0.tgz", + "integrity": "sha512-Z7FCahC4MLfTVzEwnKOB7P1fiR9DzFuMzHOPRNaMXc/rsS7unbtBKAG94yvsRzReCyjzZUVA7h37lnQ1DoPKJw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1", @@ -3766,62 +3709,62 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz", - "integrity": "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, "node_modules/@nivo/annotations": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.96.0.tgz", - "integrity": "sha512-lZRUhJyKKK5NWGU5vjEz3I2sJFFHw8TX25BefC0dJiFTliLnJqN+kSRPTWjUDPjGUPCt7vIOhISWvppNtaZG7A==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.99.0.tgz", + "integrity": "sha512-jCuuXPbvpaqaz4xF7k5dv0OT2ubn5Nt0gWryuTe/8oVsC/9bzSuK8bM9vBty60m9tfO+X8vUYliuaCDwGksC2g==", "license": "MIT", "dependencies": { - "@nivo/colors": "0.96.0", - "@nivo/core": "0.96.0", - "@nivo/theming": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2", + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", "lodash": "^4.17.21" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/axes": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.96.0.tgz", - "integrity": "sha512-/HojEQsnbADYguNciTzUAmcXpt6yk6hPHzjfqCSuzCajSofRODewx/tyJkiwpYjB/uO6XYQ54O2p9R2SJMhTTQ==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.99.0.tgz", + "integrity": "sha512-3KschnmEL0acRoa7INSSOSEFwJLm54aZwSev7/r8XxXlkgRBriu6ReZy/FG0wfN+ljZ4GMvx+XyIIf6kxzvrZg==", "license": "MIT", "dependencies": { - "@nivo/core": "0.96.0", - "@nivo/scales": "0.96.0", - "@nivo/text": "0.96.0", - "@nivo/theming": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2", + "@nivo/core": "0.99.0", + "@nivo/scales": "0.99.0", + "@nivo/text": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", "@types/d3-format": "^1.4.1", "@types/d3-time-format": "^2.3.1", "d3-format": "^1.4.4", "d3-time-format": "^3.0.0" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/colors": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.96.0.tgz", - "integrity": "sha512-kF5re/cDJXcrgecTStOl0Ld3hblRWtv3eGnfUkGFdIqACk/UM05+O1+u+adt23K16xobNKGkwVz09g1bFLOngQ==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.99.0.tgz", + "integrity": "sha512-hyYt4lEFIfXOUmQ6k3HXm3KwhcgoJpocmoGzLUqzk7DzuhQYJo+4d5jIGGU0N/a70+9XbHIdpKNSblHAIASD3w==", "license": "MIT", "dependencies": { - "@nivo/core": "0.96.0", - "@nivo/theming": "0.96.0", + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", "@types/d3-color": "^3.0.0", "@types/d3-scale": "^4.0.8", "@types/d3-scale-chromatic": "^3.0.0", @@ -3831,18 +3774,18 @@ "lodash": "^4.17.21" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/core": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.96.0.tgz", - "integrity": "sha512-iMwNyaY+XHAyTTs+GhGrdnnsDe4XAdern0+2YQca3cxyIN1pOAWbV8fUoc02VC470xoF1RkVt1C7WGUpeZCsGg==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.99.0.tgz", + "integrity": "sha512-olCItqhPG3xHL5ei+vg52aB6o+6S+xR2idpkd9RormTTUniZb8U2rOdcQojOojPY5i9kVeQyLFBpV4YfM7OZ9g==", "license": "MIT", "dependencies": { - "@nivo/theming": "0.96.0", - "@nivo/tooltip": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2", + "@nivo/theming": "0.99.0", + "@nivo/tooltip": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", "@types/d3-shape": "^3.1.6", "d3-color": "^3.1.0", "d3-format": "^1.4.4", @@ -3851,60 +3794,62 @@ "d3-scale-chromatic": "^3.0.0", "d3-shape": "^3.2.0", "d3-time-format": "^3.0.0", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "react-virtualized-auto-sizer": "^1.0.26", + "use-debounce": "^10.0.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nivo/donate" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/legends": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.96.0.tgz", - "integrity": "sha512-lZtbXHIEiOI9eMT/Fol56JyuV9zIwaVuoLlQO1BXfiM6bcTuA9A6VAPP3AQjVYI9AdEq9RRAtdfQCMrrCS0cIQ==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.99.0.tgz", + "integrity": "sha512-P16FjFqNceuTTZphINAh5p0RF0opu3cCKoWppe2aRD9IuVkvRm/wS5K1YwMCxDzKyKh5v0AuTlu9K6o3/hk8hA==", "license": "MIT", "dependencies": { - "@nivo/colors": "0.96.0", - "@nivo/core": "0.96.0", - "@nivo/text": "0.96.0", - "@nivo/theming": "0.96.0", + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/text": "0.99.0", + "@nivo/theming": "0.99.0", "@types/d3-scale": "^4.0.8", "d3-scale": "^4.0.2" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/line": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.96.0.tgz", - "integrity": "sha512-h+hVTie+nn20Yqvar3gM35tB+4fyDiq5RbWM8rQJJTE48M5uWfsnEo4klw0fYbeOgHJzsheuyTd5ZrXG4wA/lA==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.99.0.tgz", + "integrity": "sha512-bAqTXSjpnpcGMs341qWFUi7hJTqQiNoSeJHsYPuPS3icuXPcp3WETQH+zRZACeEF79ZigeOWCW+dzODgne1y9w==", "license": "MIT", "dependencies": { - "@nivo/annotations": "0.96.0", - "@nivo/axes": "0.96.0", - "@nivo/colors": "0.96.0", - "@nivo/core": "0.96.0", - "@nivo/legends": "0.96.0", - "@nivo/scales": "0.96.0", - "@nivo/theming": "0.96.0", - "@nivo/tooltip": "0.96.0", - "@nivo/voronoi": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2", + "@nivo/annotations": "0.99.0", + "@nivo/axes": "0.99.0", + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/legends": "0.99.0", + "@nivo/scales": "0.99.0", + "@nivo/theming": "0.99.0", + "@nivo/tooltip": "0.99.0", + "@nivo/voronoi": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", "@types/d3-shape": "^3.1.6", "d3-shape": "^3.2.0" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/scales": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.96.0.tgz", - "integrity": "sha512-X+d1U0AZOBqoX3h3w2fWvP3ang/7uvh+0iUlzWUsAPhooFwLCwRrgs1Emg2kUHi8D+VGjTjvWYpGBiCYEuvcyQ==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.99.0.tgz", + "integrity": "sha512-g/2K4L6L8si6E2BWAHtFVGahtDKbUcO6xHJtlIZMwdzaJc7yB16EpWLK8AfI/A42KadLhJSJqBK3mty+c7YZ+w==", "license": "MIT", "dependencies": { "@types/d3-interpolate": "^3.0.4", @@ -3925,61 +3870,61 @@ "license": "MIT" }, "node_modules/@nivo/text": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/text/-/text-0.96.0.tgz", - "integrity": "sha512-zuxi1uC12xp7+gbtTvkYXypG2xoCu9o8yoKlQcd4uTpF8d2aHqQFFaFRh9Zu4EJvp6mi+zV2D5Ywa+cItg4/8A==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/text/-/text-0.99.0.tgz", + "integrity": "sha512-ho3oZpAZApsJNjsIL5WJSAdg/wjzTBcwo1KiHBlRGUmD+yUWO8qp7V+mnYRhJchwygtRVALlPgZ/rlcW2Xr/MQ==", "license": "MIT", "dependencies": { - "@nivo/core": "0.96.0", - "@nivo/theming": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2" + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/theming": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/theming/-/theming-0.96.0.tgz", - "integrity": "sha512-Ujdg973yfDy6Gp6b6oqIOjVmMeYpoqNT1gPtzO6yWr37kdnOaw0AV5XACroX3ysYfcLR/bx3q0j+xTuhLKf/1A==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/theming/-/theming-0.99.0.tgz", + "integrity": "sha512-KvXlf0nqBzh/g2hAIV9bzscYvpq1uuO3TnFN3RDXGI72CrbbZFTGzprPju3sy/myVsauv+Bb+V4f5TZ0jkYKRg==", "license": "MIT", "dependencies": { "lodash": "^4.17.21" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/tooltip": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.96.0.tgz", - "integrity": "sha512-GNvKIt8veYe8m8yrhYJ9AVFPdvBIjqYCDKX97/qsdHmsto+NAKVp001YuJ301VvifZwLog5KUEkwfePKeiR7rQ==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.99.0.tgz", + "integrity": "sha512-weoEGR3xAetV4k2P6k96cdamGzKQ5F2Pq+uyDaHr1P3HYArM879Pl+x+TkU0aWjP6wgUZPx/GOBiV1Hb1JxIqg==", "license": "MIT", "dependencies": { - "@nivo/core": "0.96.0", - "@nivo/theming": "0.96.0", - "@react-spring/web": "9.4.5 || ^9.7.2" + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/voronoi": { - "version": "0.96.0", - "resolved": "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.96.0.tgz", - "integrity": "sha512-BjVfuwpq+NiC8Q0LXT0K83u0FBVj89WPx+WsOTtm+M2VKrcDLYMKIVJelDwY+KSpSXWSdAaOaUkAYsfaDBl5SA==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.99.0.tgz", + "integrity": "sha512-KfmMdidbYzhiUCki1FG4X4nHEFT4loK8G5bMBnmCl9U+S78W+gvkfrgD2Aoqp/Q9yKQvr3Y8UcZKSFZnn3HgjQ==", "license": "MIT", "dependencies": { - "@nivo/core": "0.96.0", - "@nivo/theming": "0.96.0", - "@nivo/tooltip": "0.96.0", + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@nivo/tooltip": "0.99.0", "@types/d3-delaunay": "^6.0.4", "@types/d3-scale": "^4.0.8", "d3-delaunay": "^6.0.4", "d3-scale": "^4.0.2" }, "peerDependencies": { - "react": ">= 16.14.0 < 20.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@noble/ciphers": { @@ -4089,86 +4034,86 @@ } }, "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", "license": "Hippocratic-2.1", "peerDependencies": { "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^19.0.0", + "react-dom": "^19.0.0" } }, "node_modules/@react-spring/animated": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", - "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-10.0.1.tgz", + "integrity": "sha512-BGL3hA66Y8Qm3KmRZUlfG/mFbDPYajgil2/jOP0VXf2+o2WPVmcDps/eEgdDqgf5Pv9eBbyj7LschLMuSjlW3Q==", "license": "MIT", "dependencies": { - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spring/core": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", - "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-10.0.1.tgz", + "integrity": "sha512-KaMMsN1qHuVTsFpg/5ajAVye7OEqhYbCq0g4aKM9bnSZlDBBYpO7Uf+9eixyXN8YEbF+YXaYj9eoWDs+npZ+sA==", "license": "MIT", "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" + "@react-spring/animated": "~10.0.1", + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/react-spring/donate" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spring/rafz": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", - "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-10.0.1.tgz", + "integrity": "sha512-UrzG/d6Is+9i0aCAjsjWRqIlFFiC4lFqFHrH63zK935z2YDU95TOFio4VKGISJ5SG0xq4ULy7c1V3KU+XvL+Yg==", "license": "MIT" }, "node_modules/@react-spring/shared": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", - "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-10.0.1.tgz", + "integrity": "sha512-KR2tmjDShPruI/GGPfAZOOLvDgkhFseabjvxzZFFggJMPkyICLjO0J6mCIoGtdJSuHywZyc4Mmlgi+C88lS00g==", "license": "MIT", "dependencies": { - "@react-spring/rafz": "~9.7.5", - "@react-spring/types": "~9.7.5" + "@react-spring/rafz": "~10.0.1", + "@react-spring/types": "~10.0.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spring/types": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", - "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-10.0.1.tgz", + "integrity": "sha512-Fk1wYVAKL+ZTYK+4YFDpHf3Slsy59pfFFvnnTfRjQQFGlyIo4VejPtDs3CbDiuBjM135YztRyZjIH2VbycB+ZQ==", "license": "MIT" }, "node_modules/@react-spring/web": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", - "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.1.tgz", + "integrity": "sha512-FgQk02OqFrYyJBTTnBTWAU0WPzkHkKXauc6aeexcvATvLapUxwnfGuLlsLYF8BYjEVfkivPT04ziAue6zyRBtQ==", "license": "MIT", "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/core": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" + "@react-spring/animated": "~10.0.1", + "@react-spring/core": "~10.0.1", + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@rtsao/scc": { @@ -4564,9 +4509,9 @@ "license": "MIT" }, "node_modules/@types/leaflet": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.17.tgz", - "integrity": "sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA==", + "version": "1.9.18", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.18.tgz", + "integrity": "sha512-ht2vsoPjezor5Pmzi5hdsA7F++v5UGq9OlUduWHmMZiuQGIpJ2WS5+Gg9HaAA79gNh1AIPtCqhzejcIZ3lPzXQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4574,9 +4519,9 @@ } }, "node_modules/@types/node": { - "version": "22.15.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", - "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "version": "22.15.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.23.tgz", + "integrity": "sha512-7Ec1zaFPF4RJ0eXu1YT/xgiebqwqoJz8rYPDi/O2BcZ++Wpt0Kq9cl0eg6NN6bYbPnR67ZLo7St5Q3UK0SnARw==", "dev": true, "license": "MIT", "dependencies": { @@ -4596,18 +4541,18 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.1.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.3.tgz", - "integrity": "sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==", + "version": "19.1.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.6.tgz", + "integrity": "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==", "license": "MIT", "dependencies": { "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "19.1.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.3.tgz", - "integrity": "sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==", + "version": "19.1.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.5.tgz", + "integrity": "sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4670,19 +4615,19 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", - "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz", + "integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/type-utils": "8.32.0", - "@typescript-eslint/utils": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/type-utils": "8.33.0", + "@typescript-eslint/utils": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, @@ -4694,22 +4639,32 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.33.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz", - "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz", + "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4" }, "engines": { @@ -4724,15 +4679,16 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz", - "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.0.tgz", + "integrity": "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0" + "@typescript-eslint/tsconfig-utils": "^8.33.0", + "@typescript-eslint/types": "^8.33.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4742,15 +4698,50 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz", - "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.0.tgz", + "integrity": "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/utils": "8.32.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz", + "integrity": "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.0.tgz", + "integrity": "sha512-lScnHNCBqL1QayuSrWeqAL5GmqNdVUQAAMTaCwdYEdWfIrSrOGzyLGRCHXcCixa5NK6i5l0AfSO2oBSjCjf4XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/utils": "8.33.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -4767,9 +4758,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz", - "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", "dev": true, "license": "MIT", "engines": { @@ -4781,14 +4772,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz", - "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.0.tgz", + "integrity": "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", + "@typescript-eslint/project-service": "8.33.0", + "@typescript-eslint/tsconfig-utils": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4834,9 +4827,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -4847,16 +4840,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz", - "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.0.tgz", + "integrity": "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0" + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4871,13 +4864,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz", - "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.0.tgz", + "integrity": "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -4902,9 +4895,9 @@ } }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.2.tgz", - "integrity": "sha512-vxtBno4xvowwNmO/ASL0Y45TpHqmNkAaDtz4Jqb+clmcVSSl8XCG/PNFFkGsXXXS6AMjP+ja/TtNCFFa1QwLRg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.3.tgz", + "integrity": "sha512-ND4wYfTQI6Cnq6+JvlebtJvGMzHmV4zXLKljAredGv4NwS1SWKdTURH64M9Yw3qZRmDqbSGn90e6axa2jVd32w==", "cpu": [ "arm64" ], @@ -4916,9 +4909,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.2.tgz", - "integrity": "sha512-qhVa8ozu92C23Hsmv0BF4+5Dyyd5STT1FolV4whNgbY6mj3kA0qsrGPe35zNR3wAN7eFict3s4Rc2dDTPBTuFQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.3.tgz", + "integrity": "sha512-zrRoLxQ1CGg4kvuDLU9ehCRGFd8TTVdh5G7NRMwt5r/vr5/QPvI2KNM1rBnMQ/p+9KBewlFcT7tMXEMe5ywLwg==", "cpu": [ "x64" ], @@ -4930,9 +4923,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.2.tgz", - "integrity": "sha512-zKKdm2uMXqLFX6Ac7K5ElnnG5VIXbDlFWzg4WJ8CGUedJryM5A3cTgHuGMw1+P5ziV8CRhnSEgOnurTI4vpHpg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.3.tgz", + "integrity": "sha512-RM5oviK7F92HZuArZocCl4PQHaaXkS3ofZyHer7kkS2VNRSLpOD6DKioWaGdzrV/LE3AwQf6W7y7awQ4OiqMfw==", "cpu": [ "x64" ], @@ -4944,9 +4937,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.2.tgz", - "integrity": "sha512-8N1z1TbPnHH+iDS/42GJ0bMPLiGK+cUqOhNbMKtWJ4oFGzqSJk/zoXFzcQkgtI63qMcUI7wW1tq2usZQSb2jxw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.3.tgz", + "integrity": "sha512-5N8ntE4dsZJXiiLqnefd4/dQvMKLs7iqcCDB/k0i2KHBQkIY9u6lsS9dI5kIgTMFV2g5lVAOSDm2HyAbdpF/oQ==", "cpu": [ "arm" ], @@ -4958,9 +4951,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.2.tgz", - "integrity": "sha512-tjYzI9LcAXR9MYd9rO45m1s0B/6bJNuZ6jeOxo1pq1K6OBuRMMmfyvJYval3s9FPPGmrldYA3mi4gWDlWuTFGA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.3.tgz", + "integrity": "sha512-w4FhO7HDQLhWAwS5tLhxzQtCbMpeI49S1J6cvBttnpirZd9pViNvQPGXXvLEtoKLbHz/QztvZqU1caqZGzzgQw==", "cpu": [ "arm" ], @@ -4972,9 +4965,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.2.tgz", - "integrity": "sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.3.tgz", + "integrity": "sha512-RJldrMcrJn2p44Uxz8CuspHCdafVZOAxfUv3yP9AWX7Q3F3ahXBXoNsrORtzsS+0ZMGN9pyz3qs8ntCa4j3Img==", "cpu": [ "arm64" ], @@ -4986,9 +4979,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.2.tgz", - "integrity": "sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.3.tgz", + "integrity": "sha512-irbhzOq9JLvp21rxmHGGs9HuDczZbquy6XLKPI4n3Tw2nVG5dFg63cVR4AeqOG1k1pKFEIdMivMAz9wx7xwXZA==", "cpu": [ "arm64" ], @@ -5000,9 +4993,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.2.tgz", - "integrity": "sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.3.tgz", + "integrity": "sha512-hVGQaBQ/jwqi2FeWFTlFCmPMMO9TZ54uisgvYOwTyhXm70JnhDrBlaNJVQrgMYyCVmGGu+IlndCYcLLiYerWnQ==", "cpu": [ "ppc64" ], @@ -5014,9 +5007,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.2.tgz", - "integrity": "sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.3.tgz", + "integrity": "sha512-FjGB+J+tNyKR1h6gm1+wGzp2EdDqXBOS33e2c7Iz6F6cIJxuGrbhw4F1Hr/HmICE3JLp8ODNi+h+1eK+5D8PCA==", "cpu": [ "riscv64" ], @@ -5028,9 +5021,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.2.tgz", - "integrity": "sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.3.tgz", + "integrity": "sha512-ZiPGSYaHXC49MBSQnW55SAAqw46QUL4Q6GtPtp/3iSEf4KLr0Wz1wmp0y1m9126sO5SMIhV7vzgOe9F5sBw1Lg==", "cpu": [ "riscv64" ], @@ -5042,9 +5035,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.2.tgz", - "integrity": "sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.3.tgz", + "integrity": "sha512-GduxPPeL5O/lP+AOSiNYh8jZTllsJ0xbq9g6GKjrhtx56MO0EvqPmodrZK29Dl4Oa55s5c/jymObsYe2MlDTWw==", "cpu": [ "s390x" ], @@ -5056,9 +5049,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.2.tgz", - "integrity": "sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.3.tgz", + "integrity": "sha512-U+ZsvSj41FU5yZ8smcW/oyygRsjOEqhPsMdsL3E6TfLFE1wDoLKgt2SL4GY33Sy+o3kigOEpYbsFy3CUXrYmsg==", "cpu": [ "x64" ], @@ -5070,9 +5063,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.2.tgz", - "integrity": "sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.3.tgz", + "integrity": "sha512-ESJHg0tdk13rXMtMjC8wveCrBBX0shwZjpJT9mHkOocdsCoQWY6wD2jRDOqUxnMfrF0OQ2bqZQNoIWqMKyZsDw==", "cpu": [ "x64" ], @@ -5084,9 +5077,9 @@ ] }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.2.tgz", - "integrity": "sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.3.tgz", + "integrity": "sha512-rseJbVdntjdI6gj7c8BnBJKa38c3Tv1XmLJ+Hu9DrGOLP5MfmqjdiIRjPuDWt3xOdWzPRnME6OOI/tuAcC0Q+A==", "cpu": [ "wasm32" ], @@ -5094,16 +5087,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.9" + "@napi-rs/wasm-runtime": "^0.2.10" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.2.tgz", - "integrity": "sha512-gtYTh4/VREVSLA+gHrfbWxaMO/00y+34htY7XpioBTy56YN2eBjkPrY1ML1Zys89X3RJDKVaogzwxlM1qU7egg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.3.tgz", + "integrity": "sha512-H+7T2Kfvj7xwiWkloqKWQeBmPcilUIv/FcC6dIvex3rzS9KdLTyF1iLygI9b7jfS8V5mpQ3V6FL91XyCPNufTA==", "cpu": [ "arm64" ], @@ -5115,9 +5108,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.2.tgz", - "integrity": "sha512-Ywv20XHvHTDRQs12jd3MY8X5C8KLjDbg/jyaal/QLKx3fAShhJyD4blEANInsjxW3P7isHx1Blt56iUDDJO3jg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.3.tgz", + "integrity": "sha512-Yu3fhFh8vJzzKMkFu+At4rWgbc7BBBqjRz6TAscXYvpSwhGyhHP7AXv6jDT+thZYZHXFlC8NK7RAXgssS/m/Zg==", "cpu": [ "ia32" ], @@ -5129,9 +5122,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.2.tgz", - "integrity": "sha512-friS8NEQfHaDbkThxopGk+LuE5v3iY0StruifjQEt7SLbA46OnfgMO15sOTkbpJkol6RB+1l1TYPXh0sCddpvA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.3.tgz", + "integrity": "sha512-G3aLTm98U9LUGMxVwedEaqWSYID78u1Bxvi5w72GdDpb1DD9pVXc5fRdqzDCApQ657mnEbLZ5YzCoe3zKH8NVQ==", "cpu": [ "x64" ], @@ -5373,20 +5366,6 @@ "dev": true, "license": "Apache-2.0" }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -6127,27 +6106,6 @@ "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "license": "MIT" }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -6296,16 +6254,6 @@ "node": ">=6.14.2" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -6387,9 +6335,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001717", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz", - "integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==", + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", "funding": [ { "type": "opencollective", @@ -6616,29 +6564,6 @@ "dev": true, "license": "MIT" }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -6646,23 +6571,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" + "node": ">=18" } }, "node_modules/core-js-compat": { @@ -6686,20 +6600,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -6839,9 +6739,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -7151,9 +7051,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "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.3" @@ -7267,16 +7167,6 @@ "robust-predicates": "^3.0.2" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -7437,17 +7327,10 @@ "node": ">= 0.4" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, "node_modules/electron-to-chromium": { - "version": "1.5.151", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.151.tgz", - "integrity": "sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==", + "version": "1.5.159", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.159.tgz", + "integrity": "sha512-CEvHptWAMV5p6GJ0Lq8aheyvVbfzVrv5mmidu1D3pidoVNkB3tTBsTMVtPJ+rzRK5oV229mCLz9Zj/hNvU8GBA==", "license": "ISC" }, "node_modules/emittery": { @@ -7479,16 +7362,6 @@ "node": ">= 4" } }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -7546,9 +7419,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "version": "1.23.10", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz", + "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==", "dev": true, "license": "MIT", "dependencies": { @@ -7556,18 +7429,18 @@ "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -7583,13 +7456,13 @@ "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", + "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", @@ -7602,7 +7475,7 @@ "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -7775,13 +7648,6 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -7795,9 +7661,9 @@ } }, "node_modules/eslint": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", - "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7805,14 +7671,13 @@ "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.26.0", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", - "@modelcontextprotocol/sdk": "^1.8.0", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -7836,8 +7701,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "zod": "^3.24.2" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -7874,9 +7738,9 @@ } }, "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -7928,6 +7792,31 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-import-context": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.6.tgz", + "integrity": "sha512-/e2ZNPDLCrU8niIy0pddcvXuoO2YrKjf3NAIX+60mHJBT4yv7mqCqvVdyCW2E720e25e4S/1OSVef4U6efGLFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash": "^0.0.5" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -7951,18 +7840,19 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.3.4.tgz", - "integrity": "sha512-buzw5z5VtiQMysYLH9iW9BV04YyZebsw+gPi+c4FCjfS9i6COYOrEWw9t3m3wA9PFBfqcBCqWf32qrXLbwafDw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.1.tgz", + "integrity": "sha512-KHQnjMAn/Hbs1AcMs2YfJTeNoWsaOoMRvJUKr77Y2dv7jNOaT8/IJYlvfN/ZIwTxUsv2B6amwv7u9bt2Vl9lZg==", "dev": true, "license": "ISC", "dependencies": { - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.5", + "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.3" + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.2" }, "engines": { "node": "^16.17.0 || >=18.6.0" @@ -8174,9 +8064,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -8449,16 +8339,6 @@ "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -8479,29 +8359,6 @@ "node": ">=0.8.x" } }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", - "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -8552,65 +8409,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, "node_modules/ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -8855,24 +8653,6 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -8943,26 +8723,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -9147,9 +8907,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9202,9 +8962,9 @@ "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.1.0.tgz", - "integrity": "sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "dev": true, "license": "MIT", "engines": { @@ -9488,23 +9248,6 @@ "entities": "^2.0.0" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -9516,9 +9259,9 @@ } }, "node_modules/i18next": { - "version": "25.1.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.1.2.tgz", - "integrity": "sha512-SP63m8LzdjkrAjruH7SCI3ndPSgjt4/wX7ouUUOzCW/eY+HzlIo19IQSfYA9X3qRiRP1SYtaTsg/Oz/PGsfD8w==", + "version": "25.2.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz", + "integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==", "funding": [ { "type": "individual", @@ -9535,7 +9278,7 @@ ], "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.10" + "@babel/runtime": "^7.27.1" }, "peerDependencies": { "typescript": "^5" @@ -9564,19 +9307,6 @@ "cross-fetch": "4.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", @@ -9738,16 +9468,6 @@ "node": ">=10.13.0" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -9836,9 +9556,9 @@ } }, "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -10062,13 +9782,6 @@ "node": ">=0.10.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==", - "dev": true, - "license": "MIT" - }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -10285,9 +9998,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -10852,9 +10565,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -10966,9 +10679,9 @@ } }, "node_modules/js-sha256": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.0.tgz", - "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz", + "integrity": "sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==", "license": "MIT" }, "node_modules/js-tokens": { @@ -11355,9 +11068,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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": { @@ -11400,29 +11113,6 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "license": "CC0-1.0" }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", - "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", @@ -11455,9 +11145,9 @@ } }, "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", "engines": { @@ -11465,13 +11155,13 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "^1.54.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -11526,6 +11216,7 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, "funding": [ { "type": "github", @@ -11541,9 +11232,9 @@ } }, "node_modules/napi-postinstall": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.3.tgz", - "integrity": "sha512-Mi7JISo/4Ij2tDZ2xBE2WH+/KvVlkhA6juEjpEeRAVPNCpN3nxJo/5FhDNKgBcdmcmhaH6JjgST4xY/23ZYK0w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", "dev": true, "license": "MIT", "bin": { @@ -11563,16 +11254,6 @@ "dev": true, "license": "MIT" }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -11684,9 +11365,9 @@ "optional": true }, "node_modules/npm": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.3.0.tgz", - "integrity": "sha512-luthFIP0nFX3+nTfYbWI3p4hP4CiVnKOZ5jdxnF2x7B+Shz8feiSJCLLzgJUNxQ2cDdTaVUiH6RRsMT++vIMZg==", + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.4.1.tgz", + "integrity": "sha512-/O5DiEFmtvnF0EU1+5VlDpcItpSKH3l+3fQOl3hkZ3ilGN+jJlGxxi/zb0rEK+zxd8pGyifVPyS1ORkMjZGAKw==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -11765,16 +11446,16 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.0.2", - "@npmcli/config": "^10.2.0", + "@npmcli/arborist": "^9.1.1", + "@npmcli/config": "^10.3.0", "@npmcli/fs": "^4.0.0", "@npmcli/map-workspaces": "^4.0.2", "@npmcli/package-json": "^6.1.1", "@npmcli/promise-spawn": "^8.0.2", "@npmcli/redact": "^3.1.1", "@npmcli/run-script": "^9.1.0", - "@sigstore/tuf": "^3.0.0", - "abbrev": "^3.0.0", + "@sigstore/tuf": "^3.1.1", + "abbrev": "^3.0.1", "archy": "~1.0.0", "cacache": "^19.0.1", "chalk": "^5.4.1", @@ -11784,21 +11465,21 @@ "fs-minipass": "^3.0.3", "glob": "^10.4.5", "graceful-fs": "^4.2.11", - "hosted-git-info": "^8.0.2", + "hosted-git-info": "^8.1.0", "ini": "^5.0.0", - "init-package-json": "^8.0.0", + "init-package-json": "^8.2.1", "is-cidr": "^5.1.1", "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^10.0.0", - "libnpmdiff": "^8.0.2", - "libnpmexec": "^10.1.1", - "libnpmfund": "^7.0.2", + "libnpmaccess": "^10.0.1", + "libnpmdiff": "^8.0.4", + "libnpmexec": "^10.1.3", + "libnpmfund": "^7.0.4", "libnpmorg": "^8.0.0", - "libnpmpack": "^9.0.2", + "libnpmpack": "^9.0.4", "libnpmpublish": "^11.0.0", "libnpmsearch": "^9.0.0", - "libnpmteam": "^8.0.0", - "libnpmversion": "^8.0.0", + "libnpmteam": "^8.0.1", + "libnpmversion": "^8.0.1", "make-fetch-happen": "^14.0.3", "minimatch": "^9.0.5", "minipass": "^7.1.1", @@ -11820,7 +11501,7 @@ "proc-log": "^5.0.0", "qrcode-terminal": "^0.12.0", "read": "^4.1.0", - "semver": "^7.7.1", + "semver": "^7.7.2", "spdx-expression-parse": "^4.0.0", "ssri": "^12.0.0", "supports-color": "^10.0.0", @@ -11946,7 +11627,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.0.2", + "version": "9.1.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -11993,7 +11674,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "10.2.0", + "version": "10.3.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -12100,7 +11781,7 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "6.1.1", + "version": "6.2.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -12128,11 +11809,11 @@ } }, "node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.0", + "version": "4.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.1.2" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^18.17.0 || >=20.5.0" @@ -12191,7 +11872,7 @@ } }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.4.0", + "version": "0.4.1", "inBundle": true, "license": "Apache-2.0", "engines": { @@ -12215,11 +11896,11 @@ } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "3.1.0", + "version": "3.1.1", "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.4.0", + "@sigstore/protobuf-specs": "^0.4.1", "tuf-js": "^3.0.1" }, "engines": { @@ -12227,13 +11908,13 @@ } }, "node_modules/npm/node_modules/@sigstore/verify": { - "version": "2.1.0", + "version": "2.1.1", "inBundle": true, "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0" + "@sigstore/protobuf-specs": "^0.4.1" }, "engines": { "node": "^18.17.0 || >=20.5.0" @@ -12260,7 +11941,7 @@ } }, "node_modules/npm/node_modules/abbrev": { - "version": "3.0.0", + "version": "3.0.1", "inBundle": true, "license": "ISC", "engines": { @@ -12325,7 +12006,7 @@ } }, "node_modules/npm/node_modules/binary-extensions": { - "version": "3.0.0", + "version": "3.1.0", "inBundle": true, "license": "MIT", "engines": { @@ -12665,7 +12346,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { - "version": "8.0.2", + "version": "8.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -12676,7 +12357,7 @@ } }, "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.1", + "version": "4.2.0", "inBundle": true, "license": "BSD-2-Clause" }, @@ -12744,7 +12425,7 @@ } }, "node_modules/npm/node_modules/init-package-json": { - "version": "8.0.0", + "version": "8.2.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -12861,7 +12542,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "10.0.0", + "version": "10.0.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -12873,11 +12554,11 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.0.2", + "version": "8.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.0.2", + "@npmcli/arborist": "^9.1.1", "@npmcli/installed-package-contents": "^3.0.0", "binary-extensions": "^3.0.0", "diff": "^7.0.0", @@ -12891,11 +12572,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "10.1.1", + "version": "10.1.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.0.2", + "@npmcli/arborist": "^9.1.1", "@npmcli/package-json": "^6.1.1", "@npmcli/run-script": "^9.0.1", "ci-info": "^4.0.0", @@ -12912,11 +12593,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.2", + "version": "7.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.0.2" + "@npmcli/arborist": "^9.1.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -12935,11 +12616,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "9.0.2", + "version": "9.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.0.2", + "@npmcli/arborist": "^9.1.1", "@npmcli/run-script": "^9.0.1", "npm-package-arg": "^12.0.0", "pacote": "^21.0.0" @@ -12978,7 +12659,7 @@ } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "8.0.0", + "version": "8.0.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -12990,7 +12671,7 @@ } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "8.0.0", + "version": "8.0.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -13527,7 +13208,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.1.2", + "version": "7.1.0", "inBundle": true, "license": "MIT", "dependencies": { @@ -13646,7 +13327,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.7.1", + "version": "7.7.2", "inBundle": true, "license": "ISC", "bin": { @@ -13908,11 +13589,11 @@ "license": "MIT" }, "node_modules/npm/node_modules/tinyglobby": { - "version": "0.2.12", + "version": "0.2.13", "inBundle": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -13923,7 +13604,7 @@ } }, "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", + "version": "6.4.4", "inBundle": true, "license": "MIT", "peerDependencies": { @@ -14294,19 +13975,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -14480,16 +14148,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/pascal-case": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", @@ -14537,16 +14195,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -14585,16 +14233,6 @@ "node": ">= 6" } }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -14692,6 +14330,7 @@ "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -14716,15 +14355,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "license": "MIT", - "peerDependencies": { - "postcss": "^8.1.4" - } - }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", @@ -14932,20 +14562,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -14978,22 +14594,6 @@ "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==", "license": "MIT" }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15025,40 +14625,11 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -15077,16 +14648,15 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.1.0" } }, "node_modules/react-draggable": { @@ -15131,9 +14701,9 @@ } }, "node_modules/react-i18next": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.1.tgz", - "integrity": "sha512-C8RZ7N7H0L+flitiX6ASjq9p5puVJU1Z8VyL3OgM/QOMRf40BMZX+5TkpxzZVcTmOLPX5zlti4InEX5pFyiVeA==", + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.2.tgz", + "integrity": "sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", @@ -15174,17 +14744,35 @@ "license": "MIT" }, "node_modules/react-leaflet": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", - "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", "license": "Hippocratic-2.1", "dependencies": { - "@react-leaflet/core": "^2.1.0" + "@react-leaflet/core": "^3.0.0" }, "peerDependencies": { "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/react-leaflet-markercluster": { + "version": "5.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz", + "integrity": "sha512-jWa4bPD5LfLV3Lid1RWgl+yKUuQtnqeYtJzzLb/fiRjvX+rtwzY8pMoUFuygqyxNrWxMTQlWKBHxkpI7Sxvu4Q==", + "license": "MIT", + "dependencies": { + "@react-leaflet/core": "^3.0.0", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react-leaflet": "^5.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react": "^19.0.0", + "react-leaflet": "^5.0.0" } }, "node_modules/react-qr-code": { @@ -15214,9 +14802,9 @@ } }, "node_modules/react-router": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", - "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.1.tgz", + "integrity": "sha512-hPJXXxHJZEsPFNVbtATH7+MMX43UDeOauz+EAU4cgqTn7ojdI9qQORqS8Z0qmDlL1TclO/6jLRYUEtbWidtdHQ==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -15236,12 +14824,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz", - "integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.1.tgz", + "integrity": "sha512-vxU7ei//UfPYQ3iZvHuO1D/5fX3/JOqhNTbRR+WjSBWxf9bIvpWK+ftjmdfJHzPOuMQKe2fiEdG+dZX6E8uUpA==", "license": "MIT", "dependencies": { - "react-router": "7.6.0" + "react-router": "7.6.1" }, "engines": { "node": ">=20.0.0" @@ -15251,15 +14839,6 @@ "react-dom": ">=18" } }, - "node_modules/react-router/node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/react-smooth-image": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/react-smooth-image/-/react-smooth-image-1.1.0.tgz", @@ -15288,6 +14867,16 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", + "integrity": "sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==", + "license": "MIT", + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-world-flags": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/react-world-flags/-/react-world-flags-1.6.0.tgz", @@ -15651,23 +15240,6 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", "license": "Unlicense" }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -15775,13 +15347,10 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" }, "node_modules/schema-utils": { "version": "2.7.1", @@ -15810,29 +15379,6 @@ "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==", - "dev": true, - "license": "MIT", - "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/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -15843,22 +15389,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/set-cookie-parser": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", @@ -15914,13 +15444,6 @@ "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==", - "dev": true, - "license": "ISC" - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -16144,16 +15667,6 @@ "node": ">=8" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/stream-buffers": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", @@ -16506,14 +16019,13 @@ } }, "node_modules/synckit": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz", - "integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.6.tgz", + "integrity": "sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.3", - "tslib": "^2.8.1" + "@pkgr/core": "^0.2.4" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -16523,9 +16035,9 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, "license": "MIT", "engines": { @@ -16550,14 +16062,14 @@ } }, "node_modules/terser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", - "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.40.0.tgz", + "integrity": "sha512-cfeKl/jjwSR5ar7d0FGmave9hFGJT8obyo0z+CrQOylLDbk7X81nPU6vq9VORa5jU30SkDnT2FXjLbR8HLP+xA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -16735,9 +16247,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -16752,9 +16264,9 @@ } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", "dev": true, "license": "MIT", "peerDependencies": { @@ -16799,16 +16311,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -16957,21 +16459,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -17074,15 +16561,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.0.tgz", - "integrity": "sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.0.tgz", + "integrity": "sha512-5YmNhF24ylCsvdNW2oJwMzTbaeO4bg90KeGtMjUw0AGtHksgEPLRTUil+coHwCfiu4QjVJFnjp94DmU6zV7DhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.32.0", - "@typescript-eslint/parser": "8.32.0", - "@typescript-eslint/utils": "8.32.0" + "@typescript-eslint/eslint-plugin": "8.33.0", + "@typescript-eslint/parser": "8.33.0", + "@typescript-eslint/utils": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17176,20 +16663,10 @@ "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/unrs-resolver": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.2.tgz", - "integrity": "sha512-BBKpaylOW8KbHsu378Zky/dGh4ckT/4NW/0SHRABdqRLcQJ2dAOjDo9g97p04sWflm0kqPqpUatxReNV/dqI5A==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.3.tgz", + "integrity": "sha512-AVTaGmPRRPefNaP2egU/QAi/kl29H9mwl6pYTS6EmUHn8+0K2uYQOgIiNBbkv6zviUHCJSYgXin03etx1K2htw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -17200,23 +16677,23 @@ "url": "https://github.com/sponsors/JounQin" }, "optionalDependencies": { - "@unrs/resolver-binding-darwin-arm64": "1.7.2", - "@unrs/resolver-binding-darwin-x64": "1.7.2", - "@unrs/resolver-binding-freebsd-x64": "1.7.2", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.2", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.2", - "@unrs/resolver-binding-linux-arm64-gnu": "1.7.2", - "@unrs/resolver-binding-linux-arm64-musl": "1.7.2", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.2", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.2", - "@unrs/resolver-binding-linux-riscv64-musl": "1.7.2", - "@unrs/resolver-binding-linux-s390x-gnu": "1.7.2", - "@unrs/resolver-binding-linux-x64-gnu": "1.7.2", - "@unrs/resolver-binding-linux-x64-musl": "1.7.2", - "@unrs/resolver-binding-wasm32-wasi": "1.7.2", - "@unrs/resolver-binding-win32-arm64-msvc": "1.7.2", - "@unrs/resolver-binding-win32-ia32-msvc": "1.7.2", - "@unrs/resolver-binding-win32-x64-msvc": "1.7.2" + "@unrs/resolver-binding-darwin-arm64": "1.7.3", + "@unrs/resolver-binding-darwin-x64": "1.7.3", + "@unrs/resolver-binding-freebsd-x64": "1.7.3", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.3", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.3", + "@unrs/resolver-binding-linux-arm64-gnu": "1.7.3", + "@unrs/resolver-binding-linux-arm64-musl": "1.7.3", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.3", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.3", + "@unrs/resolver-binding-linux-riscv64-musl": "1.7.3", + "@unrs/resolver-binding-linux-s390x-gnu": "1.7.3", + "@unrs/resolver-binding-linux-x64-gnu": "1.7.3", + "@unrs/resolver-binding-linux-x64-musl": "1.7.3", + "@unrs/resolver-binding-wasm32-wasi": "1.7.3", + "@unrs/resolver-binding-win32-arm64-msvc": "1.7.3", + "@unrs/resolver-binding-win32-ia32-msvc": "1.7.3", + "@unrs/resolver-binding-win32-x64-msvc": "1.7.3" } }, "node_modules/update-browserslist-db": { @@ -17258,6 +16735,18 @@ "punycode": "^2.1.0" } }, + "node_modules/use-debounce": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.4.tgz", + "integrity": "sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==", + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/use-sync-external-store": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", @@ -17316,16 +16805,6 @@ "node": ">=10.12.0" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -17346,9 +16825,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, "license": "MIT", "dependencies": { @@ -17375,9 +16854,9 @@ } }, "node_modules/webpack": { - "version": "5.99.8", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", - "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "version": "5.99.9", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", + "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "dev": true, "license": "MIT", "dependencies": { @@ -17491,9 +16970,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.0.tgz", + "integrity": "sha512-77R0RDmJfj9dyv5p3bM5pOHa+X8/ZkO9c7kpDstigkC4nIDobadsfSGCwB4bKhMVxqAok8tajaoR8rirM7+VFQ==", "dev": true, "license": "MIT", "engines": { @@ -17561,29 +17040,6 @@ "dev": true, "license": "MIT" }, - "node_modules/webpack/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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/webpack/node_modules/schema-utils": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", @@ -17944,26 +17400,6 @@ "engines": { "node": ">= 10" } - }, - "node_modules/zod": { - "version": "3.24.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", - "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } } } } diff --git a/frontend/package.json b/frontend/package.json index 07fe4e82..a65bc63c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,29 +15,29 @@ "author": "", "license": "ISC", "devDependencies": { - "@babel/core": "^7.27.1", - "@babel/plugin-transform-runtime": "^7.27.1", + "@babel/core": "^7.27.3", + "@babel/plugin-transform-runtime": "^7.27.3", "@babel/preset-env": "^7.27.2", "@babel/preset-react": "^7.27.1", "@babel/preset-typescript": "^7.27.1", - "@babel/runtime": "^7.27.1", + "@babel/runtime": "^7.27.3", "@eslint/compat": "^1.2.9", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.26.0", + "@eslint/js": "^9.27.0", "@types/jest": "^29.5.14", "@types/latlon-geohash": "^2.0.4", - "@types/leaflet": "^1.9.17", - "@types/react": "^19.1.3", - "@types/react-dom": "^19.1.3", + "@types/leaflet": "^1.9.18", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.5", "@types/webpack": "^5.28.5", - "@typescript-eslint/eslint-plugin": "^8.32.0", - "@typescript-eslint/parser": "^8.32.0", + "@typescript-eslint/eslint-plugin": "^8.33.0", + "@typescript-eslint/parser": "^8.33.0", "babel-loader": "^10.0.0", "css-loader": "^7.1.2", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "eslint-config-love": "^120.0.0", "eslint-config-prettier": "^10.1.5", - "eslint-import-resolver-typescript": "^4.3.4", + "eslint-import-resolver-typescript": "^4.4.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-n": "^17.18.0", "eslint-plugin-prettier": "^5.4.0", @@ -45,19 +45,18 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "filemanager-webpack-plugin": "^8.0.0", - "globals": "^16.1.0", + "globals": "^16.2.0", "html-webpack-plugin": "^5.6.3", "jest": "^29.7.0", "prettier": "^3.5.3", "style-loader": "^4.0.0", "ts-node": "^10.9.2", "typescript": "^5.8.3", - "webpack": "^5.99.8", + "webpack": "^5.99.9", "webpack-cli": "^6.0.1" }, "dependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", - "@christopherpickering/react-leaflet-markercluster": "^1.1.0", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@mui/base": "^5.0.0-beta.70", @@ -65,34 +64,35 @@ "@mui/lab": "^7.0.0-beta.12", "@mui/material": "^7.1.0", "@mui/system": "^7.1.0", - "@mui/x-data-grid": "^8.3.1", - "@mui/x-date-pickers": "^8.3.0", - "@nivo/core": "^0.96.0", - "@nivo/line": "^0.96.0", + "@mui/x-data-grid": "^8.4.0", + "@mui/x-date-pickers": "^8.4.0", + "@nivo/core": "^0.99.0", + "@nivo/line": "^0.99.0", "base-ex": "^0.8.1", "country-flag-icons": "^1.5.19", "date-fns": "^4.1.0", "file-replace-loader": "^1.4.2", - "i18next": "^25.1.2", + "i18next": "^25.2.1", "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", "install": "^0.13.0", - "js-sha256": "^0.11.0", + "js-sha256": "^0.11.1", "latlon-geohash": "^2.0.0", "leaflet": "^1.9.4", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.13.0", - "npm": "^11.3.0", + "npm": "^11.4.1", "openpgp": "^5.11.0", - "react": "^18.3.0", + "react": "^19.1.0", "react-countdown": "^2.3.6", - "react-dom": "^18.3.0", + "react-dom": "^19.1.0", "react-grid-layout": "^1.5.1", - "react-i18next": "^15.5.1", + "react-i18next": "^15.5.2", "react-image": "^4.1.0", - "react-leaflet": "^4.2.1", + "react-leaflet": "^5.0.0", + "react-leaflet-markercluster": "^5.0.0-rc.0", "react-qr-code": "^2.0.15", - "react-router-dom": "^7.6.0", + "react-router-dom": "^7.6.1", "react-smooth-image": "^1.1.0", "react-world-flags": "^1.6.0", "reconnecting-websocket": "^4.4.0", diff --git a/frontend/src/components/Dialogs/Community.tsx b/frontend/src/components/Dialogs/Community.tsx index 7d111828..64d72c3b 100644 --- a/frontend/src/components/Dialogs/Community.tsx +++ b/frontend/src/components/Dialogs/Community.tsx @@ -26,7 +26,6 @@ interface Props { const CommunityDialog = ({ open = false, onClose }: Props): React.JSX.Element => { const { t } = useTranslation(); - const [client] = window.RobosatsSettings.split('-'); const flagProps = { width: 30, @@ -81,16 +80,11 @@ const CommunityDialog = ({ open = false, onClose }: Props): React.JSX.Element => { - if (client === 'mobile') { - window.location.href = - 'nostr:npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82'; - } else { - window.open( - 'https://njump.me/npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82', - '_blank', - 'noopener,noreferrer', - ); - } + window.open( + 'https://njump.me/nprofile1qqsyx53h3h7ec4fwlspjq0kqec5gv54t7rc48xdtq6q4y94wsw4fnjqsg3jtv', + '_blank', + 'noopener,noreferrer', + ); }} > diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index 3bec26fd..cb10725f 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -488,7 +488,7 @@ const MakerForm = ({ if (pos != null) handleAddLocation(pos); setOpenWorldmap(false); }} - zoom={maker.latitude != null && maker.longitude != null ? 6 : undefined} + zoom={maker.latitude === 0 && maker.longitude === 0 ? 2 : 6} /> diff --git a/frontend/src/components/Map/index.tsx b/frontend/src/components/Map/index.tsx index 6bc2ae11..42072a38 100644 --- a/frontend/src/components/Map/index.tsx +++ b/frontend/src/components/Map/index.tsx @@ -4,7 +4,7 @@ import { useTheme, LinearProgress } from '@mui/material'; import { DivIcon, type LeafletMouseEvent } from 'leaflet'; import { type PublicOrder } from '../../models'; import OrderTooltip from '../Charts/helpers/OrderTooltip'; -import MarkerClusterGroup from '@christopherpickering/react-leaflet-markercluster'; +import MarkerClusterGroup from 'react-leaflet-markercluster'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext'; interface MapPinProps { diff --git a/frontend/src/components/SettingsForm/index.tsx b/frontend/src/components/SettingsForm/index.tsx index ef110d38..9c4fbb07 100644 --- a/frontend/src/components/SettingsForm/index.tsx +++ b/frontend/src/components/SettingsForm/index.tsx @@ -248,6 +248,7 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): React.JSX.Element = { setSettings({ ...settings, useProxy }); diff --git a/frontend/src/components/TradeBox/EncryptedChat/index.tsx b/frontend/src/components/TradeBox/EncryptedChat/index.tsx index 6d622114..83d16fd3 100644 --- a/frontend/src/components/TradeBox/EncryptedChat/index.tsx +++ b/frontend/src/components/TradeBox/EncryptedChat/index.tsx @@ -82,7 +82,9 @@ const EncryptedChat: React.FC = ({ const wrappedEvent = nip17.wrapEvent(slot?.nostrSecKey, recipient, content); - wrappedEvent.tags.push(['expiration', (wrappedEvent.created_at + 2419200).toString()]); + const oneMonth = 2419200; + + wrappedEvent.tags.push(['expiration', (wrappedEvent.created_at + oneMonth).toString()]); federation.roboPool.sendEvent(wrappedEvent); } catch (error) { diff --git a/frontend/src/contexts/AppContext.tsx b/frontend/src/contexts/AppContext.tsx index 27394e0f..c8f46f61 100644 --- a/frontend/src/contexts/AppContext.tsx +++ b/frontend/src/contexts/AppContext.tsx @@ -251,7 +251,7 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): React }, []); useEffect(() => { - if (page === 'offers' && !worldmap) { + if (['offers', 'create'].includes(page) && !worldmap) { getWorldmapGeojson(apiClient, hostUrl) .then((data) => { setWorldmap(data); diff --git a/frontend/static/css/leaflet.css b/frontend/static/css/leaflet.css index 122123f3..947d5f31 100644 --- a/frontend/static/css/leaflet.css +++ b/frontend/static/css/leaflet.css @@ -769,8 +769,6 @@ svg.leaflet-image-layer.leaflet-interactive path { } } -/* react-leaflet-cluster https://unpkg.com/@christopherpickering/react-leaflet-markercluster@1.1.0/dist/styles.min.css */ - .marker-cluster-small { background-color: rgba(181, 226, 140, 0.6); } diff --git a/requirements.txt b/requirements.txt index 0ca9e0cf..59bcc541 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,13 @@ -django==5.1.4 +django==5.1.9 django-admin-relation-links==0.2.5 -django-celery-beat==2.7.0 +django-celery-beat==2.8.1 django-celery-results==2.6.0 django-model-utils==5.0.0 django-redis==5.4.0 -djangorestframework==3.15.2 +djangorestframework==3.16.0 channels==4.2.0 channels-redis==4.2.1 -celery==5.4.0 +celery==5.5.2 grpcio==1.67.0 googleapis-common-protos==1.70.0 grpcio-tools==1.67.0 @@ -21,11 +21,11 @@ psycopg2==2.9.10 SQLAlchemy==2.0.16 django-import-export==4.3.7 requests[socks] -shapely==2.0.6 +shapely==2.0.7 python-gnupg==0.5.3 daphne==4.1.2 drf-spectacular==0.28.0 -drf-spectacular-sidecar==2024.12.1 +drf-spectacular-sidecar==2025.5.1 django-cors-headers==4.7.0 base91==1.0.1 nostr-sdk==0.35.1 diff --git a/requirements_dev.txt b/requirements_dev.txt index 8c39ebd6..48bc97c2 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,5 @@ coverage==7.8.0 ruff==0.11.10 git+https://github.com/Reckless-Satoshi/drf-openapi-tester.git@soften-django-requirements -pre-commit==4.0.1 \ No newline at end of file +pre-commit==4.2.0 +python-dotenv[cli]==1.1.0 diff --git a/robosats/settings.py b/robosats/settings.py index f2a92677..093aad06 100644 --- a/robosats/settings.py +++ b/robosats/settings.py @@ -12,7 +12,6 @@ https://docs.djangoproject.com/en/4.0/ref/settings/ """ import json -import os import textwrap from pathlib import Path @@ -59,7 +58,7 @@ CORS_ALLOW_ALL_ORIGINS = True SESSION_COOKIE_HTTPONLY = False # Logging settings -if os.environ.get("LOG_TO_CONSOLE"): +if config("LOG_TO_CONSOLE", cast=bool, default=False): LOGGING = { "version": 1, "disable_existing_loggers": False, @@ -70,12 +69,33 @@ if os.environ.get("LOG_TO_CONSOLE"): }, "root": { "handlers": ["console"], - "level": "WARNING", + "level": config("LOGGER_LEVEL", cast=str, default="WARNING"), }, "loggers": { "api.utils": { "handlers": ["console"], - "level": "WARNING", + "level": config("LOGGER_LEVEL", cast=str, default="WARNING"), + }, + }, + } +elif config("LOG_FILE", False): + LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "file": { + "class": "logging.FileHandler", + "filename": config("LOG_FILE", cast=str), + }, + }, + "root": { + "handlers": ["file"], + "level": config("LOGGER_LEVEL", cast=str, default="WARNING"), + }, + "loggers": { + "api.utils": { + "handlers": ["file"], + "level": config("LOGGER_LEVEL", cast=str, default="WARNING"), }, }, } diff --git a/scripts/traditional/README.md b/scripts/traditional/README.md new file mode 100644 index 00000000..f9707e0e --- /dev/null +++ b/scripts/traditional/README.md @@ -0,0 +1,277 @@ +# Robosats traditional environment + +Robosats backend development and testing without docker and containers. + +Binaries needed: +* postgresql (`postgres`, `initdb`, `psql`) +* redis (`redis-server`) +* bitcoin (`bitcoind`, `bitcoin-cli`) +* cln (`lightningd`, `lightning-cli`, `holdinvoice`) +* lnd (`lnd`, `lncli`) + +## Preparation + +Postgresql and redis can be found in all linux distros and bsds. + +Some distros do not put postgresql binaries in `PATH`, if this is the +case simply link them somewhere in your `PATH`. + +Example on debian: +``` +ln -sf /usr/lib/postgresql/16/bin/postgres ~/.local/bin/ +ln -sf /usr/lib/postgresql/16/bin/initdb ~/.local/bin/ +ln -sf /usr/lib/postgresql/16/bin/psql ~/.local/bin/ +``` + +Bitcoin nodes if not already installed need to be manually downloaded. +* bitcoin core binaries can be found here: https://bitcoincore.org/en/download +* cln binaries can be found here: https://github.com/ElementsProject/lightning/releases +* holdinvoice binary can be found here: https://github.com/daywalker90/holdinvoice/releases +* lnd binaries can be found here: https://github.com/lightningnetwork/lnd/releases + +Example preparation: +``` +$ python3 -m venv venv +$ . venv/bin/activate +$ pip install -r requirements_dev.txt +$ pip install -r requirements.txt + +$ mkdir traditional +$ mkdir traditional/programs +$ cd traditional/programs + +# if you do not have them already installed +$ mkdir bitcoin cln lnd +# download bitcoin, cln (and holdinvoice) and lnd binaries + +# follow https://github.com/hoytech/strfry#compile +$ git clone https://github.com/hoytech/strfry +$ cd strfry +$ git submodule update --init +$ git checkout 1.0.4 +$ make setup-golpe +$ make -j4 + +# if you want to use roboauto +# still in traditional/programs +$ git clone https://github.com/jerryfletcher21/roboauto +$ cd roboauto +$ pip install -r requirements.txt +$ pip install . +``` + +## env file + +``` +$ cp .env-sample .env +``` +Edit `.env`, both robosats and traditional scripts will read from there. + +Variables to change: +``` +LNVENDOR = "CLN" +# LNVENDOR = "LND" + +BITCOIND_RPCURL = "http://127.0.0.1:18443" +BITCOIND_RPCUSER = "test" +BITCOIND_RPCPASSWORD = "test" +CLN_DIR = "traditional/nodes/cln-coord/regtest/" +CLN_GRPC_HOST = "localhost:9999" +CLN_GRPC_HOLD_HOST = "localhost:9998" +LND_DIR = "traditional/nodes/lnd-coord/" +MACAROON_PATH = "data/chain/bitcoin/regtest/admin.macaroon" +LND_GRPC_HOST = "localhost:10009" +# POSTGRES_DB should not be postgres +POSTGRES_DB = "robosats" +# POSTGRES_USER should not be the same as $USER environment variable +POSTGRES_USER = "robosats" +POSTGRES_PASSWORD = "robosats" +USE_TOR = False +LOG_TO_CONSOLE = True +LOGGER_LEVEL = "INFO" +``` + +Variables to add: +``` +DEVELOPMENT = True +TESTING = True +SKIP_FRONTEND_TESTS = True +TIMING_EXTRA_IN_TESTS = True + +# LNVENDOR_USER is what robosats calls robot node in tests +LNVENDOR_USER = "LND" +# LNVENDOR_USER = "CLN" + +DAPHNE_PORT = 9000 +GUNICORN_PORT = 8080 +RUNSERVER_PORT = 8000 +STRFRY_PORT = 7778 + +BITCOIND_BIN = "traditional/programs/bitcoin/bin/bitcoind" +BITCOIN_CLI_BIN = "traditional/programs/bitcoin/bin/bitcoin-cli" +LIGHTNINGD_BIN = "traditional/programs/cln/bin/lightningd" +LIGHTNING_CLI_BIN = "traditional/programs/cln/bin/lightning-cli" +HOLDINVOICE_PLUGIN_BIN = "traditional/programs/cln/holdinvoice" +LND_BIN = "traditional/programs/lnd/lnd" +LNCLI_BIN = "traditional/programs/lnd/lncli" +STRFRY_GIT_DIR = "traditional/programs/strfry" +ROBOAUTO_GIT_DIR = "traditional/programs/roboauto" +TRADITIONAL_NODES_DIR = "traditional/nodes" +TRADITIONAL_SERVICES_DIR = "traditional/services" +TRADITIONAL_LOGS_DIR = "traditional/logs" +GNUPG_DIR = "traditional/services/gnupg" + +BITCOIN_TEST_ZMQ_BLOCK_PORT = 28432 +BITCOIN_TEST_ZMQ_TX_PORT = 28433 + +# CLN_GRPC_HOST and CLN_GRPC_HOLD_HOST are for coord +CLN_TEST_COORD_LISTEN_PORT = 19846 +CLN_TEST_USER_GRPC_PORT = 9989 +CLN_TEST_USER_LISTEN_PORT = 19836 + +# LND_GRPC_HOST is for coord +LND_TEST_COORD_LISTEN_PORT = 19746 +LND_TEST_COORD_REST_PORT = 8181 +LND_TEST_COORD_MACAROON_PATH = "traditional/nodes/lnd-coord/data/chain/bitcoin/regtest/admin.macaroon" + +LND_TEST_USER_GRPC_PORT = 10010 +LND_TEST_USER_LISTEN_PORT = 19736 +LND_TEST_USER_REST_PORT = 8182 +LND_TEST_USER_MACAROON_PATH = "traditional/nodes/lnd-user/data/chain/bitcoin/regtest/admin.macaroon" +``` + +Paths can be relative or absolute. Binaries should be paths, they are +not resolved with `PATH`. + +Roboauto can be disabled by not setting `ROBOAUTO_GIT_DIR` or setting it +to `false`. + +If some ports are already in use, change their value. + +To check which port are already in use, `netstat -tulnp` with root +privileges can be used. + +For example if there is alread an instance of postgresql running on the +default port, change `POSTGRES_PORT = "5433"`. + +## Usage + +For development and testing two scripts are provided: +* `traditional-services` for non bitcoin related services +* `regtest-nodes` for bitcoin and lightning nodes + +`traditional-services` sets up the database and manages the services. + +Everything is done locally, so no root privileges/service managers are +needed. + +`regtest-nodes` is a script that should be sourced, it sets up a regtest +environment, with bitcoin core, cln, lnd and roboauto, connecting them +and creating channels. It then exposes the functions `btc_reg`, +`cln_coord`, `cln_user`, `lnd_coord`, `lnd_user`, `ra_reg` to interact +with the nodes and roboauto. + +If the script is sourced in a `bash` shell, it will also source +completions for all the functions. + +`regtest-nodes` can also be run without arguments to simply expose the +functions to start and remove the nodes and to create the channels +between them, without setting up a specific environment. + +Setup: +``` +# change .env file + +$ . venv/bin/activate + +# generate cln and lnd grpc +$ scripts/generate_grpc.sh + +$ . scripts/traditional/regtest-nodes test + +$ scripts/traditional/traditional-services postgres-setup + +$ scripts/traditional/traditional-services postgres-database + +$ scripts/traditional/traditional-services strfry-setup + +# remove the nodes +$ robosats_regtest_stop_and_remove_all + +# postgres-database will create the database specified by +# POSTGRES_DB in .env, it can be run multiple times with +# different values of POSTGRES_DB for different databases +``` + +Testing: +``` +# edit .env setting LNVENDOR to either "CLN" or "LND" +# LNVENDOR_USER while running tests should be set to "LND" + +# in the main window +$ . venv/bin/activate +$ . scripts/traditional/regtest-nodes test + +# in a secondary window +$ . venv/bin/activate +# can be stopped with Control-C +$ scripts/traditional/traditional-services test + +# back in the main window +$ python3 manage.py test + +# after having run the tests run +$ robosats_regtest_stop_and_remove_all +# to remove the nodes, they will be recreated when +# running the tests again + +# python3 manage.py test can be run multiple times with the same database +# to have a clean database either use a different value +# of POSTGRES_DB or use a different directory (and run again the setup) +# by moving traditional/services/postgres somewhere and the moving it back when +# you want to use the old database again +``` + +Development: +``` +# edit .env setting LNVENDOR to either "CLN" or "LND" +# and LNVENDOR_USER to either "CLN" or "LND" + +# in the main window +$ . venv/bin/activate +$ . scripts/traditional/regtest-nodes server + +# in a secondary window +$ . venv/bin/activate +# can be stopped with Control-C +$ scripts/traditional/traditional-services server + +# to see the output of the django runserver command +# in a third window +$ tail -f traditional/logs/runserver + +# if roboauto is active, use it to test the backend +# back in the main window +$ ra_reg --help +... +$ ra_reg create-order "$(ra_reg generate-robot --loc)" type=buy currency=btc min_amount=0.001 max_amount=0.002 payment_method="On-Chain BTC" premium=-1.5 +... +$ ra_reg take-order $(ra_reg generate-robot --loc) order-id +... +$ ra_reg escrow-pay RobotName +... +``` + +Update: +``` +$ . venv/bin/activate + +$ pip install -r requirements_dev.txt +$ pip install -r requirements.txt + +# start just postgres and redis in an other window +$ scripts/traditional/traditional-services test + +# in the main window +$ python3 manage.py migrate +``` diff --git a/scripts/traditional/regtest-nodes b/scripts/traditional/regtest-nodes new file mode 100755 index 00000000..478c017a --- /dev/null +++ b/scripts/traditional/regtest-nodes @@ -0,0 +1,1438 @@ +#!/bin/sh + +_command_exist() { + if command -v "$1" >/dev/null 2>&1; then + return 0 + else + echo "error: $1 command not found" >&2 + return 1 + fi +} + +_function_exist() { + if command -V "$1" 2>/dev/null | grep -qwi function >/dev/null 2>&1; then + return 0 + else + echo "error: function $1 not set" >&2 + return 1 + fi +} + +_create_dir() { + if [ ! -e "$1" ]; then + mkdir -p "$1" || return "$?" + elif [ ! -d "$1" ]; then + echo "error: $1 is not a directory" >&2 + return 1 + fi +} + +# if $2 is provided use it as default +# otherwise return error when not found +_get_env_var() { + if ! env_var="$(dotenv -f ".env" get "$1" 2>/dev/null)"; then + if [ "$#" -ge 2 ]; then + env_var="$2" + else + echo "error: getting $1 from .env" >&2 + return 1 + fi + fi + printf "%s\n" "$env_var" + + return 0 +} + +# transform relative path into absolute and remove trailing slashes +_get_env_var_path() { + env_var="$(_get_env_var "$@")" || return "$?" + real_path="$(realpath -m "$env_var")" || return "$?" + printf "%s\n" "$real_path" + + return 0 +} + +# extract the port from an env variable +_get_env_var_port() { + env_var="$(_get_env_var "$@")" || return "$?" + printf "%s\n" "$env_var" | + rev | + cut -d ":" -f 1 | + rev + + return 0 +} + +_nodes_environment_set() { + if [ ! -f "scripts/traditional/regtest-nodes" ]; then + echo "error: source this script from the project root" >&2 + return 1 + fi + if [ ! -f ".env" ]; then + echo "error: .env is not present" >&2 + return 1 + fi + if ! _command_exist dotenv; then + return 1 + fi + + TESTING="$(_get_env_var TESTING false)" || return "$?" + case "$(printf "%s\n" "$TESTING" | tr '[:upper:]' '[:lower:]')" in + true|yes|on|1) + TESTING=true + ;; + *) + TESTING=false + ;; + esac + + RUNSERVER_PORT="$(_get_env_var "RUNSERVER_PORT")" || return "$?" + + cln_set=false + lnd_set=false + + LNVENDOR_COORD="$(_get_env_var LNVENDOR)" || return "$?" + LNVENDOR_COORD="$(printf "%s\n" "$LNVENDOR_COORD" | tr '[:upper:]' '[:lower:]')" + case "$LNVENDOR_COORD" in + cln) cln_set=true ;; + lnd) lnd_set=true ;; + *) + echo "error: LNVENDOR can be cln or lnd" >&2 + return 1 + ;; + esac + LNVENDOR_USER="$(_get_env_var LNVENDOR_USER)" || return "$?" + LNVENDOR_USER="$(printf "%s\n" "$LNVENDOR_USER" | tr '[:upper:]' '[:lower:]')" + case "$LNVENDOR_USER" in + cln) cln_set=true ;; + lnd) lnd_set=true ;; + *) + echo "error: LNVENDOR_USER can be cln or lnd" >&2 + return 1 + ;; + esac + if [ "$TESTING" = true ] && [ "$LNVENDOR_USER" != "lnd" ]; then + echo "error: LNVENDOR_USER should be lnd when running tests" >&2 + return 1 + fi + + BITCOIND_BIN="$(_get_env_var_path "BITCOIND_BIN")" || return "$?" + BITCOIN_CLI_BIN="$(_get_env_var_path "BITCOIN_CLI_BIN")" || return "$?" + if [ "$cln_set" = true ]; then + LIGHTNINGD_BIN="$(_get_env_var_path "LIGHTNINGD_BIN")" || return "$?" + LIGHTNING_CLI_BIN="$(_get_env_var_path "LIGHTNING_CLI_BIN")" || return "$?" + HOLDINVOICE_PLUGIN_BIN="$(_get_env_var_path "HOLDINVOICE_PLUGIN_BIN")" || return "$?" + fi + if [ "$lnd_set" = true ]; then + LND_BIN="$(_get_env_var_path "LND_BIN")" || return "$?" + LNCLI_BIN="$(_get_env_var_path "LNCLI_BIN")" || return "$?" + fi + REGTEST_NODES_DIR="$(_get_env_var_path "TRADITIONAL_NODES_DIR")" || return "$?" + REGTEST_LOGS_DIR="$(_get_env_var_path "TRADITIONAL_LOGS_DIR")" || return "$?" + + ROBOAUTO_GIT_DIR="$(_get_env_var_path "ROBOAUTO_GIT_DIR" false)" || return "$?" + + BITCOIN_REGTEST_RPC_PORT="$(_get_env_var_port "BITCOIND_RPCURL")" || return "$?" + BITCOIN_REGTEST_RPC_USER="$(_get_env_var "BITCOIND_RPCUSER")" || return "$?" + BITCOIN_REGTEST_RPC_PASS="$(_get_env_var "BITCOIND_RPCPASSWORD")" || return "$?" + BITCOIN_REGTEST_ZMQ_BLOCK_PORT="$(_get_env_var "BITCOIN_TEST_ZMQ_BLOCK_PORT")" || return "$?" + BITCOIN_REGTEST_ZMQ_TX_PORT="$(_get_env_var "BITCOIN_TEST_ZMQ_TX_PORT")" || return "$?" + + if [ "$cln_set" = true ]; then + CLN_COORD_GRPC_PORT="$(_get_env_var_port "CLN_GRPC_HOST")" || return "$?" + CLN_COORD_HOLD_PORT="$(_get_env_var_port "CLN_GRPC_HOLD_HOST")" || return "$?" + CLN_COORD_LISTEN_PORT="$(_get_env_var "CLN_TEST_COORD_LISTEN_PORT")" || return "$?" + + CLN_USER_GRPC_PORT="$(_get_env_var "CLN_TEST_USER_GRPC_PORT")" || return "$?" + CLN_USER_LISTEN_PORT="$(_get_env_var "CLN_TEST_USER_LISTEN_PORT")" || return "$?" + fi + if [ "$lnd_set" = true ]; then + LND_COORD_RPC_PORT="$(_get_env_var_port "LND_GRPC_HOST")" || return "$?" + LND_COORD_LISTEN_PORT="$(_get_env_var "LND_TEST_COORD_LISTEN_PORT")" || return "$?" + LND_COORD_REST_PORT="$(_get_env_var "LND_TEST_COORD_REST_PORT")" || return "$?" + + LND_USER_RPC_PORT="$(_get_env_var "LND_TEST_USER_GRPC_PORT")" || return "$?" + LND_USER_LISTEN_PORT="$(_get_env_var "LND_TEST_USER_LISTEN_PORT")" || return "$?" + LND_USER_REST_PORT="$(_get_env_var "LND_TEST_USER_REST_PORT")" || return "$?" + fi + + if [ -z "$BITCOIND_BIN" ]; then + BITCOIND_BIN="bitcoind" + fi + if ! _command_exist "$BITCOIND_BIN"; then + return 1 + fi + if [ -z "$BITCOIN_CLI_BIN" ]; then + BITCOIN_CLI_BIN="bitcoin-cli" + fi + if ! _command_exist "$BITCOIN_CLI_BIN"; then + return 1 + fi + + if [ "$cln_set" = true ]; then + if [ -z "$LIGHTNINGD_BIN" ]; then + LIGHTNINGD_BIN="lightningd" + fi + if ! _command_exist "$LIGHTNINGD_BIN"; then + return 1 + fi + if [ -z "$LIGHTNING_CLI_BIN" ]; then + LIGHTNING_CLI_BIN="lightning-cli" + fi + if ! _command_exist "$LIGHTNING_CLI_BIN"; then + return 1 + fi + if [ -z "$HOLDINVOICE_PLUGIN_BIN" ]; then + echo "error: $HOLDINVOICE_PLUGIN_BIN not set" >&2 + return 1 + fi + if [ ! -f "$HOLDINVOICE_PLUGIN_BIN" ]; then + echo "error: $HOLDINVOICE_PLUGIN_BIN plugin not found" >&2 + return 1 + fi + fi + + if [ "$lnd_set" = true ]; then + if [ -z "$LND_BIN" ]; then + LND_BIN="lnd" + fi + if ! _command_exist "$LND_BIN"; then + return 1 + fi + if [ -z "$LNCLI_BIN" ]; then + LNCLI_BIN="lncli" + fi + if ! _command_exist "$LNCLI_BIN"; then + return 1 + fi + fi + + if [ -z "$REGTEST_NODES_DIR" ]; then + echo "error: REGTEST_NODES_DIR not set" >&2 + return 1 + fi + _create_dir "$REGTEST_NODES_DIR" || return "$?" + + if [ -z "$REGTEST_LOGS_DIR" ]; then + echo "error: REGTEST_LOGS_DIR not set" >&2 + return 1 + fi + _create_dir "$REGTEST_LOGS_DIR" || return "$?" + + BITCOIN_DIR="$REGTEST_NODES_DIR/bitcoin" + ROBOAUTO_DIR="$REGTEST_NODES_DIR/roboauto" + + if [ "$cln_set" = true ]; then + CLN_COORD_DIR="$REGTEST_NODES_DIR/cln-coord" + CLN_USER_DIR="$REGTEST_NODES_DIR/cln-user" + + cln_coor_dir_env="$(_get_env_var_path "CLN_DIR")" || return "$?" + if [ "$cln_coor_dir_env" != "$CLN_COORD_DIR/regtest" ]; then + echo "error: CLN_DIR not consistent with REGTEST_NODES_DIR" >&2 + return 1 + fi + fi + + if [ "$lnd_set" = true ]; then + LND_COORD_DIR="$REGTEST_NODES_DIR/lnd-coord" + LND_USER_DIR="$REGTEST_NODES_DIR/lnd-user" + + lnd_coord_dir_env="$(_get_env_var_path "LND_DIR")" || return "$?" + if [ "$lnd_coord_dir_env" != "$LND_COORD_DIR" ]; then + echo "error: LND_DIR not consistent with REGTEST_NODES_DIR" >&2 + return 1 + fi + + correct_macaroon_path="data/chain/bitcoin/regtest/admin.macaroon" + macaroon_path="$( + _get_env_var "MACAROON_PATH" + )" || return "$?" + if [ "$macaroon_path" != "$correct_macaroon_path" ]; then + echo "error: MACAROON_PATH should be $correct_macaroon_path" >&2 + return 1 + fi + + lnd_test_coord_macaroon_path="$( + _get_env_var_path "LND_TEST_COORD_MACAROON_PATH" + )" || return "$?" + if [ \ + "$lnd_test_coord_macaroon_path" != \ + "$LND_COORD_DIR/$correct_macaroon_path" \ + ]; then + echo "error: LND_TEST_COORD_MACAROON_PATH not consistent with REGTEST_NODES_DIR" >&2 + return 1 + fi + + lnd_test_user_macaroon_path="$( + _get_env_var_path "LND_TEST_USER_MACAROON_PATH" + )" || return "$?" + if [ \ + "$lnd_test_user_macaroon_path" != \ + "$LND_USER_DIR/$correct_macaroon_path" \ + ]; then + echo "error: LND_TEST_USER_MACAROON_PATH not consistent with REGTEST_NODES_DIR" >&2 + return 1 + fi + fi +} + +_pgrep_bitcoin_regtest() { + pgrep -f "$BITCOIND_BIN -datadir=$BITCOIN_DIR -regtest -daemon" >/dev/null +} + +_bitcoin_regtest_check_started() { + if ! _pgrep_bitcoin_regtest; then + echo "error: bitcoin regtest not started" >&2 + return 1 + fi + if ! _function_exist btc_reg; then + return 1 + fi + return 0 +} + +bitcoin_regtest_mine() { + _bitcoin_regtest_check_started || return "$?" + + if [ "$#" -lt 2 ]; then + return 1 + fi + if [ "$2" = "new" ]; then + if ! new_address="$(btc_reg getnewaddress)"; then + echo "error: could not create new address" >&2 + return 1 + fi + else + new_address="$2" + fi + if ! new_block_hash="$( + btc_reg -named generatetoaddress nblocks="$1" address="$new_address" | + jq -r '.[-1]' + )"; then + echo "error: could not generate to $new_address" >&2 + return 1 + fi + while [ "$(btc_reg getbestblockhash)" != "$new_block_hash" ]; do + echo "waiting for $1 blocks to be mined..." + sleep 1 + done + unset new_block_hash + echo "mined $1 blocks to $new_address" + unset new_address +} + +bitcoin_regtest_start() { + _create_dir "$BITCOIN_DIR" || return "$?" + + echo "writing bitcoin regtest config" + cat << EOF > "$BITCOIN_DIR/bitcoin.conf" +txindex=1 +rest=1 +server=1 +logips=1 +listenonion=0 +zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT +zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT +[regtest] +rpcport=$BITCOIN_REGTEST_RPC_PORT +rpcuser=$BITCOIN_REGTEST_RPC_USER +rpcpassword=$BITCOIN_REGTEST_RPC_PASS +EOF + + if ! _pgrep_bitcoin_regtest; then + echo "starting bitcoin regtest" + if ! "$BITCOIND_BIN" -datadir="$BITCOIN_DIR" -regtest -daemon >/dev/null; then + echo "error: starting bitcoind regtest daemon" >&2 + return 1 + fi + else + echo "bitcoin regtest already started" + fi + + btc_reg() { + "$BITCOIN_CLI_BIN" \ + -datadir="$BITCOIN_DIR" \ + -regtest \ + -rpcuser="$BITCOIN_REGTEST_RPC_USER" \ + -rpcpassword="$BITCOIN_REGTEST_RPC_PASS" \ + "$@" + } + + # wait for bitcoin to start + while ! btc_reg ping >/dev/null 2>&1; do + echo "waiting for bitcoind regtes to start..." + sleep 1 + done + + # check if default wallet exists + if + ! btc_reg listwalletdir | + jq -r '.wallets[] | .name' | + grep "^default$" >/dev/null 2>&1 + then + if ! btc_reg -named createwallet \ + wallet_name=default \ + disable_private_keys=false \ + blank=false \ + avoid_reuse=false \ + descriptors=true \ + load_on_startup=true \ + external_signer=false >/dev/null + then + echo "error: could not create default wallet" >&2 + return 1 + fi + echo "default bitcoind wallet successfully created" + fi + + # check if default wallet is loaded + if + ! btc_reg listwallets | + jq -r '.[]' | + grep "^default$" >/dev/null 2>&1 + then + if ! btc_reg loadwallet default; then + echo "error: could not load default wallet" >&2 + return 1 + fi + echo "default bitcoind wallet successfully loaded" + fi + + bitcoin_regtest_mine 1 "new" || return "$?" + while [ "$(btc_reg getblockchaininfo | jq -r '.initialblockdownload')" != false ]; do + echo "waiting for bitcoind regtes to download blocks..." + sleep 1 + done + + echo "bitcoin regtest started, data directory is $BITCOIN_DIR" + echo "btc_reg function set" +} + +_bitcoin_regtest_stop() { + if ! _pgrep_bitcoin_regtest; then + echo "bitcoin regtest already stopped" + else + if + ! "$BITCOIN_CLI_BIN" \ + -datadir="$BITCOIN_DIR" \ + -regtest \ + stop >/dev/null + then + echo "error: bitcoin regtest not stopped" >&2 + fi + + while _pgrep_bitcoin_regtest; do + echo "waiting for bitcoin regtest to stop..." + sleep 1 + done + echo "bitcoin regtest stopped" + fi +} + +bitcoin_regtest_stop_and_remove() { + _bitcoin_regtest_stop || return "$?" + + if [ ! -e "$BITCOIN_DIR" ]; then + echo "bitcoin directory not present" + else + if ! rm -rf "$BITCOIN_DIR"; then + echo "error: removing bitcoin directory $BITCOIN_DIR" + return 1 + fi + echo "removed bitcoin directory $BITCOIN_DIR" + fi +} + +_pgrep_cln_coord() { + pgrep -f \ + "$LIGHTNINGD_BIN --lightning-dir=$CLN_COORD_DIR --regtest --daemon" \ + >/dev/null +} + +cln_coord_start() { + _bitcoin_regtest_check_started || return "$?" + + _create_dir "$CLN_COORD_DIR" || return "$?" + + echo "writing cln coordinator config" + cat << EOF > "$CLN_COORD_DIR/config" +bitcoin-cli=$BITCOIN_CLI_BIN +bitcoin-datadir=$BITCOIN_DIR +bitcoin-rpcuser=$BITCOIN_REGTEST_RPC_USER +bitcoin-rpcpassword=$BITCOIN_REGTEST_RPC_PASS +bitcoin-rpcport=$BITCOIN_REGTEST_RPC_PORT +alias=cln-coordinator +rgb=100000 +fee-base=0 +fee-per-satoshi=0 +min-capacity-sat=990000 +ignore-fee-limits=true +funding-confirms=1 +max-concurrent-htlcs=64 +max-dust-htlc-exposure-msat=1000000000 +cltv-delta=144 +cltv-final=144 +bitcoin-retry-timeout=120 +database-upgrade=true +log-file=lightning.log +addr=localhost:$CLN_COORD_LISTEN_PORT +grpc-port=$CLN_COORD_GRPC_PORT +important-plugin=$HOLDINVOICE_PLUGIN_BIN +grpc-hold-port=$CLN_COORD_HOLD_PORT +disable-plugin=clnrest +disable-plugin=wss-proxy +EOF + + if ! _pgrep_cln_coord; then + echo "starting cln coordinator" + if + ! "$LIGHTNINGD_BIN" \ + --lightning-dir="$CLN_COORD_DIR" \ + --regtest \ + --daemon \ + >/dev/null + then + echo "error: starting cln coordinator daemon" >&2 + return 1 + fi + else + echo "cln coordinator already started" + fi + + cln_coord() { + "$LIGHTNING_CLI_BIN" \ + --lightning-dir="$CLN_COORD_DIR" \ + --regtest \ + "$@" + } + + while [ \ + "$(cln_coord getinfo | jq -r '.blockheight')" -ne \ + "$(btc_reg getblockcount)" \ + ]; do + echo "waiting for cln coordinator to sync with the chain..." + sleep 1 + done + + echo "cln coordinator started, data directory is $CLN_COORD_DIR" + echo "cln_coord function set" +} + +_cln_coord_stop() { + if ! _pgrep_cln_coord; then + echo "cln coordinator already stopped" + else + if + ! "$LIGHTNING_CLI_BIN" \ + --lightning-dir="$CLN_COORD_DIR" \ + --regtest \ + stop >/dev/null + then + echo "error: cln coordinator not stopped" >&2 + fi + + while _pgrep_cln_coord; do + echo "waiting for cln coordinator to stop..." + sleep 1 + done + echo "cln coordinator stopped" + fi +} + +cln_coord_stop_and_remove() { + _cln_coord_stop || return "$?" + + if [ ! -e "$CLN_COORD_DIR" ]; then + echo "cln coordinator directory not present" + else + if ! rm -rf "$CLN_COORD_DIR"; then + echo "error: removing cln coordinator directory $CLN_COORD_DIR" + return 1 + fi + echo "removed cln coordinator directory $CLN_COORD_DIR" + fi +} + +_pgrep_cln_user() { + pgrep -f \ + "$LIGHTNINGD_BIN --lightning-dir=$CLN_USER_DIR --regtest --daemon" \ + >/dev/null +} + +cln_user_start() { + _bitcoin_regtest_check_started || return "$?" + + _create_dir "$CLN_USER_DIR" || return "$?" + + echo "writing cln user config" + cat << EOF > "$CLN_USER_DIR/config" +bitcoin-cli=$BITCOIN_CLI_BIN +bitcoin-datadir=$BITCOIN_DIR +bitcoin-rpcuser=$BITCOIN_REGTEST_RPC_USER +bitcoin-rpcpassword=$BITCOIN_REGTEST_RPC_PASS +bitcoin-rpcport=$BITCOIN_REGTEST_RPC_PORT +alias=cln-user +rgb=200000 +fee-base=0 +fee-per-satoshi=0 +min-capacity-sat=990000 +ignore-fee-limits=true +funding-confirms=1 +max-concurrent-htlcs=64 +max-dust-htlc-exposure-msat=1000000000 +cltv-delta=144 +cltv-final=144 +bitcoin-retry-timeout=120 +database-upgrade=true +log-file=lightning.log +addr=localhost:$CLN_USER_LISTEN_PORT +grpc-port=$CLN_USER_GRPC_PORT +disable-plugin=clnrest +disable-plugin=wss-proxy +EOF + + if ! _pgrep_cln_user; then + echo "starting cln user" + if + ! "$LIGHTNINGD_BIN" \ + --lightning-dir="$CLN_USER_DIR" \ + --regtest \ + --daemon \ + >/dev/null + then + echo "error: starting cln user daemon" >&2 + return 1 + fi + else + echo "cln user already started" + fi + + cln_user() { + "$LIGHTNING_CLI_BIN" \ + --lightning-dir="$CLN_USER_DIR" \ + --regtest \ + "$@" + } + + while [ \ + "$(cln_user getinfo | jq -r '.blockheight')" -ne \ + "$(btc_reg getblockcount)" \ + ]; do + echo "waiting for cln user to sync with the chain..." + sleep 1 + done + + echo "cln user started, data directory is $CLN_USER_DIR" + echo "cln_user function set" +} + +_cln_user_stop() { + if ! _pgrep_cln_user; then + echo "cln user already stopped" + else + if + ! "$LIGHTNING_CLI_BIN" \ + --lightning-dir="$CLN_USER_DIR" \ + --regtest \ + stop >/dev/null + then + echo "error: cln user not stopped" >&2 + fi + + while _pgrep_cln_user; do + echo "waiting for cln user to stop..." + sleep 1 + done + echo "cln user stopped" + fi +} + +cln_user_stop_and_remove() { + _cln_user_stop || return "$?" + + if [ ! -e "$CLN_USER_DIR" ]; then + echo "cln user directory not present" + else + if ! rm -rf "$CLN_USER_DIR"; then + echo "error: removing cln user directory $CLN_USER_DIR" + return 1 + fi + echo "removed cln user directory $CLN_USER_DIR" + fi +} + +_pgrep_lnd_coord() { + pgrep -f "$LND_BIN --lnddir=$LND_COORD_DIR --bitcoin.regtest" >/dev/null +} + +lnd_coord_start() { + _bitcoin_regtest_check_started || return "$?" + + _create_dir "$LND_COORD_DIR" || return "$?" + + echo "writing lnd coordinator config" + cat << EOF > "$LND_COORD_DIR/lnd.conf" +[Application Options] +listen=localhost:$LND_COORD_LISTEN_PORT +rpclisten=localhost:$LND_COORD_RPC_PORT +restlisten=localhost:$LND_COORD_REST_PORT +no-rest-tls=true +tlsdisableautofill=true +noseedbackup=true +maxpendingchannels=16 +minchansize=20000 +alias=lnd-coordinator +color=#300000 + +[Bitcoin] +bitcoin.node=bitcoind +bitcoin.defaultchanconfs=1 +bitcoin.basefee=0 +bitcoin.feerate=0 + +[Bitcoind] +bitcoind.dir=$BITCOIN_DIR +bitcoind.config=$BITCOIN_DIR/bitcoin.conf +bitcoind.rpchost=localhost:$BITCOIN_REGTEST_RPC_PORT +bitcoind.rpcuser=$BITCOIN_REGTEST_RPC_USER +bitcoind.rpcpass=$BITCOIN_REGTEST_RPC_PASS +bitcoind.zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT +bitcoind.zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT + +[protocol] +protocol.wumbo-channels=true +EOF + + if ! _pgrep_lnd_coord; then + echo "starting lnd coordinator" + "$LND_BIN" \ + --lnddir="$LND_COORD_DIR" \ + --bitcoin.regtest \ + >"$REGTEST_LOGS_DIR/lnd-coord" 2>&1 & + else + echo "lnd coordinator already started" + fi + + lnd_coord() { + "$LNCLI_BIN" \ + --lnddir="$LND_COORD_DIR" \ + --network regtest \ + --rpcserver localhost:"$LND_COORD_RPC_PORT" \ + "$@" + } + + while [ "$(lnd_coord getinfo 2>/dev/null | jq -r '.synced_to_chain')" != true ]; do + echo "waiting for lnd coordinator to sync with the chain..." + sleep 1 + done + + # while [ "$(lnd_coord getinfo 2>/dev/null | jq -r '.synced_to_graph')" != true ]; do + # echo "waiting for lnd coordinator to sync with the graph..." + # sleep 1 + # done + + echo "lnd coordinator started, data directory is $LND_COORD_DIR" + echo "lnd_coord function set" +} + +_lnd_coord_stop() { + if ! _pgrep_lnd_coord; then + echo "lnd coordinator already stopped" + else + if + ! "$LNCLI_BIN" \ + --lnddir="$LND_COORD_DIR" \ + --network regtest \ + --rpcserver localhost:"$LND_COORD_RPC_PORT" \ + stop >/dev/null + then + echo "error: lnd coordinator not stopped" >&2 + fi + + while _pgrep_lnd_coord; do + echo "waiting for lnd coordinator to stop..." + sleep 1 + done + echo "lnd coordinator stopped" + fi +} + +lnd_coord_stop_and_remove() { + _lnd_coord_stop || return "$?" + + if [ ! -e "$LND_COORD_DIR" ]; then + echo "lnd coordinator directory not present" + else + if ! rm -rf "$LND_COORD_DIR"; then + echo "error: removing lnd coordinator directory $LND_COORD_DIR" + return 1 + fi + echo "removed lnd coordinator directory $LND_COORD_DIR" + fi +} + +_pgrep_lnd_user() { + pgrep -f "$LND_BIN --lnddir=$LND_USER_DIR --bitcoin.regtest" >/dev/null +} + +lnd_user_start() { + _bitcoin_regtest_check_started || return "$?" + + _create_dir "$LND_USER_DIR" || return "$?" + + echo "writing lnd user config" + cat << EOF > "$LND_USER_DIR/lnd.conf" +[Application Options] +listen=localhost:$LND_USER_LISTEN_PORT +rpclisten=localhost:$LND_USER_RPC_PORT +restlisten=localhost:$LND_USER_REST_PORT +no-rest-tls=true +tlsdisableautofill=true +noseedbackup=true +maxpendingchannels=16 +minchansize=20000 +alias=lnd-user +color=#400000 + +[Bitcoin] +bitcoin.node=bitcoind +bitcoin.defaultchanconfs=1 +bitcoin.basefee=0 +bitcoin.feerate=0 + +[Bitcoind] +bitcoind.dir=$BITCOIN_DIR +bitcoind.config=$BITCOIN_DIR/bitcoin.conf +bitcoind.rpchost=localhost:$BITCOIN_REGTEST_RPC_PORT +bitcoind.rpcuser=$BITCOIN_REGTEST_RPC_USER +bitcoind.rpcpass=$BITCOIN_REGTEST_RPC_PASS +bitcoind.zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT +bitcoind.zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT + +[protocol] +protocol.wumbo-channels=true +EOF + + if ! _pgrep_lnd_user; then + echo "starting lnd user" + "$LND_BIN" \ + --lnddir="$LND_USER_DIR" \ + --bitcoin.regtest \ + >"$REGTEST_LOGS_DIR/lnd-user" 2>&1 & + else + echo "lnd user already started" + fi + + lnd_user() { + "$LNCLI_BIN" \ + --lnddir="$LND_USER_DIR" \ + --network regtest \ + --rpcserver localhost:"$LND_USER_RPC_PORT" \ + "$@" + } + + while [ "$(lnd_user getinfo 2>/dev/null | jq -r '.synced_to_chain')" != true ]; do + echo "waiting for lnd user to sync with the chain..." + sleep 1 + done + + # while [ "$(lnd_user getinfo 2>/dev/null | jq -r '.synced_to_graph')" != true ]; do + # echo "waiting for lnd user to sync with the graph..." + # sleep 1 + # done + + echo "lnd user started, data directory is $LND_USER_DIR" + echo "lnd_user function set" +} + +_lnd_user_stop() { + if ! _pgrep_lnd_user; then + echo "lnd user already stopped" + else + if + ! "$LNCLI_BIN" \ + --lnddir="$LND_USER_DIR" \ + --network regtest \ + --rpcserver localhost:"$LND_USER_RPC_PORT" \ + stop >/dev/null + then + echo "error: lnd user not stopped" >&2 + fi + + while _pgrep_lnd_user; do + echo "waiting for lnd user to stop..." + sleep 1 + done + echo "lnd user stopped" + fi +} + +lnd_user_stop_and_remove() { + _lnd_user_stop || return "$?" + + if [ ! -e "$LND_USER_DIR" ]; then + echo "lnd user directory not present" + else + if ! rm -rf "$LND_USER_DIR"; then + echo "error: removing lnd user directory $LND_USER_DIR" + return 1 + fi + echo "removed lnd user directory $LND_USER_DIR" + fi +} + +_mine_blocks_coordinator() { + coord_node="$1" + case "$coord_node" in + cln) + if ! coord_address="$( + cln_coord -k newaddr addresstype=p2tr | jq -r '.p2tr' + )"; then + echo "error: generating cln coordinator address" >&2 + return 1 + fi + ;; + lnd) + if ! coord_address="$( + lnd_coord newaddress p2tr | jq -r '.address' + )"; then + echo "error: generating lnd coordinator address" >&2 + return 1 + fi + ;; + esac + + bitcoin_regtest_mine 101 "$coord_address" || return "$?" + unset user_address +} + +_robosats_regtest_channel_create_cln_user() { + if [ "$#" -lt 1 ]; then + echo "error: insert coordinator node" >&2 + return 1 + fi + coord_node="$1" + shift 1 + + _bitcoin_regtest_check_started || return "$?" + + case "$coord_node" in + cln) + if ! _pgrep_cln_coord; then + echo "error: cln coordinator not started" >&2 + return 1 + fi + if ! _function_exist cln_coord; then + return 1 + fi + coord_id="$(cln_coord getinfo | jq -r '.id')" + coord_port="$CLN_COORD_LISTEN_PORT" + ;; + lnd) + if ! _pgrep_lnd_coord; then + echo "error: cln coordinator not started" >&2 + return 1 + fi + if ! _function_exist lnd_coord; then + return 1 + fi + coord_id="$(lnd_coord getinfo | jq -r '.identity_pubkey')" + coord_port="$LND_COORD_LISTEN_PORT" + ;; + *) + echo "error: coordinator node can only be cln and lnd" >&2 + return 1 + ;; + esac + + if ! _pgrep_cln_user; then + echo "error: cln user not started" >&2 + return 1 + fi + if ! _function_exist cln_user; then + return 1 + fi + + if ! cln_user connect "$coord_id"@localhost:"$coord_port" >/dev/null; then + echo "error: connection lightning nodes" >&2 + return 1 + fi + echo "lightning nodes connected" + + # check if channel not already present + if [ "$( + cln_user listpeerchannels "$coord_id" | + jq -r '.channels | length' + )" -ge 1 ]; then + echo "lightning nodes already have a channel, not opening a new one" + else + echo "mining blocks to coordinator $coord_node" + _mine_blocks_coordinator "$coord_node" || return "$?" + + previous_output_number="$(cln_user listfunds | jq -r '.outputs | length')" + + if ! user_address="$(cln_user -k newaddr addresstype=p2tr | jq -r '.p2tr')"; then + echo "error: generating user address" >&2 + return 1 + fi + echo "mining blocks to user cln" + bitcoin_regtest_mine 101 "$user_address" || return "$?" + unset user_address + + while [ \ + "$(cln_user listfunds | jq -r '.outputs | length')" -le \ + "$previous_output_number" \ + ]; do + echo "waiting for cln user to see the new blocks..." + sleep 5 + done + while [ "$(cln_user listfunds | jq -r '.outputs[0].status')" != "confirmed" ]; do + echo "waiting for cln user funds to mature..." + sleep 1 + done + + unset previous_output_number + + if ! cln_user -k fundchannel \ + id="$coord_id" \ + amount=1btc \ + feerate=10000perkb \ + announce=true \ + >/dev/null + then + echo "error: funding lightning channel" >&2 + return 1 + fi + echo "lightning channel created" + + bitcoin_regtest_mine 10 "new" || return "$?" + while [ "$( + cln_user listpeerchannels "$coord_id" | + jq -r '.channels | length' + )" -lt 1 ]; do + echo "waiting for channel to confirm..." + sleep 1 + done + echo "lightning channel opened" + fi + + while [ "$( + cln_user listpeerchannels "$coord_id" | + jq -r '.channels[].state' + )" != "CHANNELD_NORMAL" ]; do + echo "waiting for channel to be active..." + sleep 5 + done + echo "lightning channel is active" + + unset coord_port + unset coord_id + unset coord_node +} + +_robosats_regtest_channel_create_lnd_user() { + if [ "$#" -lt 1 ]; then + echo "error: insert coordinator node" >&2 + return 1 + fi + coord_node="$1" + shift 1 + + _bitcoin_regtest_check_started || return "$?" + + case "$coord_node" in + cln) + if ! _pgrep_cln_coord; then + echo "error: cln coordinator not started" >&2 + return 1 + fi + if ! _function_exist cln_coord; then + return 1 + fi + coord_id="$(cln_coord getinfo | jq -r '.id')" + coord_port="$CLN_COORD_LISTEN_PORT" + ;; + lnd) + if ! _pgrep_lnd_coord; then + echo "error: cln coordinator not started" >&2 + return 1 + fi + if ! _function_exist lnd_coord; then + return 1 + fi + coord_id="$(lnd_coord getinfo | jq -r '.identity_pubkey')" + coord_port="$LND_COORD_LISTEN_PORT" + ;; + *) + echo "error: coordinator node can only be cln and lnd" >&2 + return 1 + ;; + esac + + if ! _pgrep_lnd_user; then + echo "error: lnd user not started" >&2 + return 1 + fi + if ! _function_exist lnd_user; then + return 1 + fi + + already_connected=false + for pub_key in $(lnd_user listpeers | jq -r '.peers[].pub_key'); do + if [ "$pub_key" = "$coord_id" ]; then + already_connected=true + break + fi + done + unset pub_key + if [ "$already_connected" = false ]; then + if ! lnd_user connect "$coord_id"@localhost:"$coord_port" >/dev/null; then + echo "error: connection lightning nodes" >&2 + return 1 + fi + fi + unset already_connected + echo "lightning nodes connected" + + # check if channel not already present + if [ "$( + lnd_user listchannels --peer "$coord_id" | + jq -r '.channels | length' + )" -ge 1 ]; then + echo "lightning nodes already have a channel, not opening a new one" + else + echo "mining blocks to coordinator $coord_node" + _mine_blocks_coordinator "$coord_node" || return "$?" + + previous_output_number="$(lnd_user listunspent | jq -r '.utxos | length')" + + if ! user_address="$(lnd_user newaddress p2tr | jq -r '.address')"; then + echo "error: generating user address" >&2 + return 1 + fi + echo "mining blocks to user lnd" + bitcoin_regtest_mine 101 "$user_address" || return "$?" + unset user_address + + while [ \ + "$(lnd_user listunspent | jq -r '.utxos | length')" -le \ + "$previous_output_number" \ + ]; do + echo "waiting for lnd user to see the new blocks..." + sleep 5 + done + while [ "$(lnd_user listunspent | jq -r '.utxos[0].confirmations')" -lt 100 ]; do + echo "waiting for lnd user funds to mature..." + sleep 1 + done + + unset previous_output_number + + if ! lnd_user openchannel \ + --node_key "$coord_id" \ + --local_amt "100000000" \ + --sat_per_vbyte "10" \ + --min_confs "1" \ + --channel_type "anchors" \ + >/dev/null + then + echo "error: funding lightning channel" >&2 + return 1 + fi + echo "lightning channel created" + + bitcoin_regtest_mine 10 "new" || return "$?" + while [ "$( + lnd_user listchannels --peer "$coord_id" | + jq -r '.channels | length' + )" -lt 1 ]; do + echo "waiting for channel to confirm..." + sleep 1 + done + echo "lightning channel opened" + fi + + while [ "$( + lnd_user listchannels --peer "$coord_id" | + jq -r '.channels[].active' + )" != true ]; do + echo "waiting for channel to be active..." + sleep 5 + done + echo "lightning channel is active" + + unset coord_port + unset coord_id + unset coord_node +} + +robosats_regtest_channel_create() { + if [ "$#" -lt 1 ]; then + echo "error: insert coordinator node" >&2 + return 1 + fi + coord_node="$1" + shift 1 + + if [ "$#" -lt 1 ]; then + echo "error: insert user node" >&2 + return 1 + fi + user_node="$1" + shift 1 + + case "$coord_node" in + cln|lnd) ;; + *) + echo "error: $coord_node should be cln or lnd" >&2 + return 1 + ;; + esac + + case "$user_node" in + cln) + _robosats_regtest_channel_create_cln_user "$coord_node" + ;; + lnd) + _robosats_regtest_channel_create_lnd_user "$coord_node" + ;; + *) + echo "error: $user_node should be cln or lnd" >&2 + return 1 + ;; + esac + + unset user_node + unset coord_node +} + +roboauto_regtest_setup() { + if [ "$ROBOAUTO_GIT_DIR" = false ]; then + echo "error: roboauto is disable, set ROBOAUTO_GIT_DIR in .env to activate it" >&2 + return 1 + fi + + _command_exist roboauto || return "$?" + + _create_dir "$ROBOAUTO_DIR" || return "$?" + + ra_reg() { + roboauto \ + --config-dir "$REGTEST_NODES_DIR/roboauto" \ + --data-dir "$REGTEST_NODES_DIR/roboauto" \ + "$@" + } + + echo "writing roboauto regtest config" + cat << EOF > "$ROBOAUTO_DIR/config.ini" +[federation] +exp = None +sau = None +tos = None +tbl = None +bve = None +loc = "http://127.0.0.1:$RUNSERVER_PORT" +EOF + + case "$LNVENDOR_USER" in + cln) + roboauto_cln_script="$ROBOAUTO_GIT_DIR/data/lightning-node-core-lightning" + if [ ! -f "$roboauto_cln_script" ]; then + echo "error: roboauto cln script not found in $ROBOAUTO_GIT_DIR" >&2 + return 1 + fi + + search_data=$(cat << EOF +lightning-cli "\$@" +EOF + ) + new_data=$(cat << EOF +"$LIGHTNING_CLI_BIN" \ +--lightning-dir="$CLN_USER_DIR" \ +--regtest \ +"\$@" +EOF + ) + sed "s|$search_data|$new_data|" \ + "$roboauto_cln_script" > "$ROBOAUTO_DIR/lightning-node" || \ + return "$?" + + echo "roboauto cln node script set up" + ;; + lnd) + roboauto_lnd_script="$ROBOAUTO_GIT_DIR/data/lightning-node-lnd" + if [ ! -f "$roboauto_lnd_script" ]; then + echo "error: roboauto lnd script not found in $ROBOAUTO_GIT_DIR" >&2 + return 1 + fi + + search_data=$(cat << EOF +lncli "\$@" +EOF + ) + new_data=$(cat << EOF +"$LNCLI_BIN" \ +--lnddir="$LND_USER_DIR" \ +--network regtest \ +--rpcserver localhost:"$LND_USER_RPC_PORT" \ +"\$@" +EOF + ) + sed "s|$search_data|$new_data|" \ + "$roboauto_lnd_script" > "$ROBOAUTO_DIR/lightning-node" || \ + return "$?" + + echo "roboauto lnd node script set up" + ;; + esac + if ! chmod u+x "$ROBOAUTO_DIR/lightning-node"; then + echo "error: changing file mode on roboauto lightning-node" >&2 + return 1 + fi +} + +roboauto_regtest_remove() { + if ! rm -rf "$ROBOAUTO_DIR"; then + echo "error: removing roboauto directory $ROBOAUTO_DIR" >&2 + return 1 + fi +} + +robosats_regtest_stop_all() { + _lnd_user_stop + _lnd_coord_stop + _cln_user_stop + _cln_coord_stop + _bitcoin_regtest_stop +} + +robosats_regtest_stop_and_remove_all() { + roboauto_regtest_remove + lnd_user_stop_and_remove + lnd_coord_stop_and_remove + cln_user_stop_and_remove + cln_coord_stop_and_remove + bitcoin_regtest_stop_and_remove +} + +_node_test_setup() { + bitcoin_regtest_start || return "$?" + + bitcoin_regtest_mine 1 "new" || return "$?" + + printf "\n" + + case "$LNVENDOR_COORD" in + cln) + cln_coord_start || return "$?" + ;; + lnd) + lnd_coord_start || return "$?" + ;; + esac + + printf "\n" + + case "$LNVENDOR_USER" in + cln) + cln_user_start || return "$?" + ;; + lnd) + lnd_user_start || return "$?" + ;; + esac +} + +_node_server_setup() { + _node_test_setup || return "$?" + + printf "\n" + + robosats_regtest_channel_create \ + "$LNVENDOR_COORD" "$LNVENDOR_USER" || return "$?" + + if [ "$ROBOAUTO_GIT_DIR" != false ]; then + printf "\n" + + roboauto_regtest_setup + fi +} + +_robosats_regtest_info_print() { + cat << EOF +regtest nodes directory is $REGTEST_NODES_DIR +available command: + +bitcoin_regtest_start +bitcoin_regtest_stop_and_remove +bitcoin_regtest_mine number-of-blocks
|new +cln_coord_start +cln_coord_stop_and_remove +cln_user_start +cln_user_stop_and_remove +lnd_coord_start +lnd_coord_stop_and_remove +lnd_user_start +lnd_user_stop_and_remove +roboauto_regtest_setup +roboauto_regtest_remove +robosats_regtest_stop_all +robosats_regtest_stop_and_remove_all +robosats_regtest_channel_create cln|lnd cln|lnd +EOF +} + +_nodes_main() { + _nodes_environment_set || return "$?" + + # if shell is bash and script is sourced source also bash completions + if [ -n "$BASH_VERSION" ]; then + case "$0" in + /*|./*|../*) ;; + *) + if [ -f "scripts/traditional/robosats.bash-completion" ]; then + # shellcheck disable=SC1091 + . scripts/traditional/robosats.bash-completion + fi + if + [ "$ROBOAUTO_GIT_DIR" != false ] && + [ -f "$ROBOAUTO_GIT_DIR/completions/roboauto.bash-completion" ] + then + # shellcheck disable=SC1091 + # shellcheck disable=SC3044 + . "$ROBOAUTO_GIT_DIR/completions/roboauto.bash-completion" && + complete -F __roboauto_completion ra_reg + fi + ;; + esac + fi + + if [ "$#" -lt 1 ]; then + _robosats_regtest_info_print || return "$?" + else + case "$1" in + -h|--help) + cat << EOF +regtest-nodes [server|test] +EOF + return 0 + ;; + test) + _robosats_regtest_info_print || return "$?" + printf "\n" + _node_test_setup || return "$?" + ;; + server) + _robosats_regtest_info_print || return "$?" + printf "\n" + _node_server_setup || return "$?" + ;; + *) + echo "error: action $1 not recognized" >&2 + return 1 + ;; + esac + fi +} + +_nodes_main "$@" diff --git a/scripts/traditional/robosats.bash-completion b/scripts/traditional/robosats.bash-completion new file mode 100755 index 00000000..2b3dee15 --- /dev/null +++ b/scripts/traditional/robosats.bash-completion @@ -0,0 +1,281 @@ +#!/usr/bin/env bash + +# adapted from +# https://github.com/bitcoin/bitcoin/blob/master/contrib/completions/bash/bitcoin-cli.bash +_bitcoin_cli() { + local cur prev words=() cword + local bitcoin_cli + + # save and use original argument to invoke bitcoin-cli for -help, help and RPC + # as bitcoin-cli might not be in $PATH + bitcoin_cli="$1" + + if ! command -v "$bitcoin_cli" >/dev/null 2>&1; then + return 0 + fi + + COMPREPLY=() + _get_comp_words_by_ref -n = cur prev words cword + + if ((cword > 5)); then + case ${words[cword-5]} in + sendtoaddress) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 4)); then + case ${words[cword-4]} in + importaddress|listtransactions|setban) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + signrawtransactionwithkey|signrawtransactionwithwallet) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 3)); then + case ${words[cword-3]} in + addmultisigaddress) + return 0 + ;; + getbalance|gettxout|importaddress|importpubkey|importprivkey|listreceivedbyaddress|listsinceblock) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 2)); then + case ${words[cword-2]} in + addnode) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) ) + return 0 + ;; + setban) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) ) + return 0 + ;; + fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listreceivedbyaddress|sendrawtransaction) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + esac + fi + + case "$prev" in + backupwallet|dumpwallet|importwallet) + _filedir + return 0 + ;; + getaddednodeinfo|getrawmempool|lockunspent) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + getbalance|getnewaddress|listtransactions|sendmany) + return 0 + ;; + esac + + # determine already specified args necessary for RPC + local rpcargs=() + local i + for i in ${COMP_LINE}; do + case "$i" in + -conf=*|-datadir=*|-rpc*|-chain=*|-testnet|-signet|-regtest) + rpcargs=( "${rpcargs[@]}" "$i" ) + ;; + esac + done + + case "$cur" in + -conf=*) + cur="${cur#*=}" + _filedir + return 0 + ;; + -datadir=*) + cur="${cur#*=}" + _filedir -d + return 0 + ;; + -rpcwallet=*) + cur="${cur#*=}" + wallets="$($bitcoin_cli "${rpcargs[@]}" listwallets | jq -r '.[]')" + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "$wallets" -- "$cur" ) ) + return 0 + ;; + -*=*) # prevent nonsense completions + return 0 + ;; + *) + local helpopts commands completions + + # only parse -help if senseful + if [[ -z "$cur" || "$cur" =~ ^- ]]; then + helpopts=$($bitcoin_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + fi + + # only parse help if senseful + if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then + commands=$($bitcoin_cli "${rpcargs[@]}" help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }') + fi + + completions="$helpopts $commands generatetoaddress" + + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "$completions" -- "$cur" ) ) + + # Prevent space if an argument is desired + local word + for word in "${COMPREPLY[@]}"; do + case "$word" in + *=) + compopt -o nospace + break + ;; + esac + done + return 0 + ;; + esac +} && +complete -F _bitcoin_cli btc_reg + +# adapted from +# https://github.com/ElementsProject/lightning/blob/master/contrib/lightning-cli.bash-completion +_lightning_cli() { + local command_name="$1" + # local current_word="$2" + local previous_word="$3" + + local lightning_cli + + # lightning_cli might not be in $PATH + lightning_cli="$command_name" + + if ! command -v "$lightning_cli" >/dev/null 2>&1; then + return 0 + fi + + if [ "${COMP_CWORD}" -eq 1 ]; then + complete_opt=true + else + case "$previous_word" in + --help|-h) complete_opt=false ;; + help|-*) complete_opt=true ;; + *) complete_opt=false ;; + esac + fi + + if [ "$complete_opt" = true ]; then + # shellcheck disable=SC2034 + local cur prev words=() cword + + COMPREPLY=() + _get_comp_words_by_ref -n = cur prev words cword + + case "$cur" in + -*=*) # prevent nonsense completions + return 0 + ;; + *) + local helpopts globalcmds + + # get the global options, starting with -- + if [[ -z "$cur" || "$cur" =~ ^- ]]; then + globalcmds="$( + $lightning_cli --help 2>&1 | + tr '|' '\n' | + sed -n -e 's/ .*//' -e 's/\(-[-a-z0-9A-Z]*\).*/\1/p' + )" + fi + + # get the regular commands + if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then + helpopts="$( + $lightning_cli help 2>/dev/null | + sed -n 's/^\([a-z][a-z_-]*\).*/\1/p' | + sed '$ d' + )" + fi + + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "$helpopts $globalcmds" -X "*," -- "$cur" ) ) + ;; + esac + else + _minimal + fi +} && +complete -F _lightning_cli cln_coord && +complete -F _lightning_cli cln_user + +# adapted from +# https://github.com/lightningnetwork/lnd/blob/master/contrib/lncli.bash-completion +_lncli() { + local cur prev words=() cword + local lncli + + # lncli might not be in $PATH + lncli="$1" + + if ! command -v "$lncli" >/dev/null 2>&1; then + return 0 + fi + + COMPREPLY=() + _get_comp_words_by_ref -n = cur prev words cword + + case "$prev" in + # example of further completion + newaddress) + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "p2wkh np2wkh" -- "$cur" ) ) + return 0 + ;; + esac + + case "$cur" in + -*=*) # prevent nonsense completions + return 0 + ;; + esac + + if [ "$cword" -eq 1 ] || { + [ "$cword" -eq 2 ] && [ "$prev" = "help" ] + }; then + local helpopts globalcmds completions + + # get the global options, starting with -- + if [[ -z "$cur" || "$cur" =~ ^- ]]; then + globalcmds=$($lncli help 2>&1 | awk '$1 ~ /^-/ { sub(/,/, ""); print $1}') + fi + + # get the regular commands + if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then + helpopts=$($lncli help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }' ) + fi + + completions="$helpopts $globalcmds help" + + # shellcheck disable=SC2207 + COMPREPLY=( $( compgen -W "$completions" -X "*," -- "$cur" ) ) + fi +} && +complete -F _lncli lnd_coord && +complete -F _lncli lnd_user diff --git a/scripts/traditional/templates/strfry.conf b/scripts/traditional/templates/strfry.conf new file mode 100644 index 00000000..2b119f08 --- /dev/null +++ b/scripts/traditional/templates/strfry.conf @@ -0,0 +1,138 @@ +## +## Default strfry config +## + +# Directory that contains the strfry LMDB database (restart required) +db = "$STRFRY_DIR/" + +dbParams { + # Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required) + maxreaders = 256 + + # Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required) + mapsize = 10995116277760 + + # Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required) + noReadAhead = false +} + +events { + # Maximum size of normalised JSON, in bytes + maxEventSize = 65536 + + # Events newer than this will be rejected + rejectEventsNewerThanSeconds = 900 + + # Events older than this will be rejected + rejectEventsOlderThanSeconds = 94608000 + + # Ephemeral events older than this will be rejected + rejectEphemeralEventsOlderThanSeconds = 60 + + # Ephemeral events will be deleted from the DB when older than this + ephemeralEventsLifetimeSeconds = 300 + + # Maximum number of tags allowed + maxNumTags = 2000 + + # Maximum size for tag values, in bytes + maxTagValSize = 1024 +} + +relay { + # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required) + bind = "127.0.0.1" + + # Port to open for the nostr websocket protocol (restart required) + port = $STRFRY_PORT + + # Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required) + nofiles = 1000000 + + # HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case) + realIpHeader = "" + + info { + # NIP-11: Name of this server. Short/descriptive (< 30 characters) + name = "Robosats" + + # NIP-11: Detailed information about relay, free-form + description = "Federation cache system." + + # NIP-11: Administrative nostr pubkey, for contact purposes + pubkey = "" + + # NIP-11: Alternative administrative contact (email, website, etc) + contact = "" + } + + # Maximum accepted incoming websocket frame size (should be larger than max event) (restart required) + maxWebsocketPayloadSize = 131072 + + # Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required) + autoPingSeconds = 55 + + # If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy) + enableTcpKeepalive = false + + # How much uninterrupted CPU time a REQ query should get during its DB scan + queryTimesliceBudgetMicroseconds = 10000 + + # Maximum records that can be returned per filter + maxFilterLimit = 500 + + # Maximum number of subscriptions (concurrent REQs) a connection can have open at any time + maxSubsPerConnection = 3 + + writePolicy { + # If non-empty, path to an executable script that implements the writePolicy plugin logic + plugin = "" + } + + compression { + # Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required) + enabled = true + + # Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required) + slidingWindow = false + } + + logging { + # Dump all incoming messages + dumpInAll = false + + # Dump all incoming EVENT messages + dumpInEvents = false + + # Dump all incoming REQ/CLOSE messages + dumpInReqs = false + + # Log performance metrics for initial REQ database scans + dbScanPerf = false + + # Log reason for invalid event rejection? Can be disabled to silence excessive logging + invalidEvents = true + } + + numThreads { + # Ingester threads: route incoming requests, validate events/sigs (restart required) + ingester = 3 + + # reqWorker threads: Handle initial DB scan for events (restart required) + reqWorker = 3 + + # reqMonitor threads: Handle filtering of new events (restart required) + reqMonitor = 3 + + # negentropy threads: Handle negentropy protocol messages (restart required) + negentropy = 2 + } + + negentropy { + # Support negentropy protocol messages + enabled = true + + # Maximum records that sync will process before returning an error + maxSyncEvents = 1000000 + } +} diff --git a/scripts/traditional/traditional-services b/scripts/traditional/traditional-services new file mode 100755 index 00000000..c2e8b723 --- /dev/null +++ b/scripts/traditional/traditional-services @@ -0,0 +1,468 @@ +#!/bin/sh + +_command_exist() { + if command -v "$1" >/dev/null 2>&1; then + return 0 + else + echo "error: $1 command not found" >&2 + return 1 + fi +} + +_create_dir() { + if [ ! -e "$1" ]; then + mkdir -p "$1" || return "$?" + if [ "$#" -ge 2 ]; then + if ! chmod "$2" "$1"; then + echo "error: setting chmod $2 of $1" >&2 + return 1 + fi + fi + elif [ ! -d "$1" ]; then + echo "error: $1 is not a directory" >&2 + return 1 + fi +} + +# if $2 is provided use it as default +# otherwise return error when not found +_get_env_var() { + if ! env_var="$(dotenv -f ".env" get "$1" 2>/dev/null)"; then + if [ "$#" -ge 2 ]; then + env_var="$2" + else + echo "error: getting $1 from .env" >&2 + return 1 + fi + fi + printf "%s\n" "$env_var" + + return 0 +} + +# transform relative path into absolute and remove trailing slashes +_get_env_var_path() { + env_var="$(_get_env_var "$@")" || return "$?" + real_path="$(realpath -m "$env_var")" || return "$?" + printf "%s\n" "$real_path" + + return 0 +} + +_services_environment_set() { + TRADITIONAL_SERVICES_DIR="$(_get_env_var_path "TRADITIONAL_SERVICES_DIR")" || return "$?" + TRADITIONAL_LOGS_DIR="$(_get_env_var_path "TRADITIONAL_LOGS_DIR")" || return "$?" + _create_dir "$TRADITIONAL_SERVICES_DIR" || return "$?" + _create_dir "$TRADITIONAL_LOGS_DIR" || return "$?" + + POSTGRES_DIR="$TRADITIONAL_SERVICES_DIR/postgres" + REDIS_DIR="$TRADITIONAL_SERVICES_DIR/redis" + STRFRY_DIR="$TRADITIONAL_SERVICES_DIR/strfry" + GNUPG_DIR="$(_get_env_var_path "GNUPG_DIR")" || return "$?" + + POSTGRES_DB="$(_get_env_var "POSTGRES_DB")" || return "$?" + POSTGRES_USER="$(_get_env_var "POSTGRES_USER")" || return "$?" + POSTGRES_PASS="$(_get_env_var "POSTGRES_PASSWORD")" || return "$?" + POSTGRES_PORT="$(_get_env_var "POSTGRES_PORT")" || return "$?" + + REDIS_URL="$(_get_env_var "REDIS_URL")" || return "$?" + REDIS_PORT="$( + printf "%s\n" "$REDIS_URL" | + rev | + cut -d ":" -f 1 | + rev | + cut -d "/" -f 1 + )" + + STRFRY_GIT_DIR="$(_get_env_var_path "STRFRY_GIT_DIR")" || return "$?" + + RUNSERVER_PORT="$(_get_env_var "RUNSERVER_PORT")" || return "$?" + STRFRY_PORT="$(_get_env_var "STRFRY_PORT")" || return "$?" + + if [ "$POSTGRES_DB" = "postgres" ]; then + echo "error: POSTGRES_DB should not be postgres" >&2 + return 1 + fi + if [ "$POSTGRES_USER" = "$USER" ]; then + echo "error: POSTGRES_USER should not be the same as USER" >&2 + return 1 + fi + + TRADITIONAL_DIR="$(realpath "$(dirname "$0")")" + + STRFRY_CONF="$STRFRY_DIR/strfry.conf" + + strfry_bin="$STRFRY_GIT_DIR/strfry" + + # to prevent having same command names and killing wrong programs + python_bin="$(which python3)" + celery_bin="$(which celery)" + + # docker-compose.yml + + RUNSERVER_COMMAND="$python_bin manage.py runserver 0.0.0.0:$RUNSERVER_PORT" + + CLEAN_ORDERS_COMMAND="$python_bin manage.py clean_orders" + FOLLOW_INVOICES_COMMAND="$python_bin manage.py follow_invoices" + # TELEGRAM_WATCHER_COMMAND="$python_bin manage.py telegram_watcher" + + CELERY_DEV_COMMAND="$celery_bin -A robosats worker --loglevel=INFO --concurrency 4 --max-tasks-per-child=4 --max-memory-per-child=200000" + CELERY_BEAT_COMMAND="$celery_bin -A robosats beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler" + + STRFRY_RELAY_COMMAND="$strfry_bin --config $STRFRY_CONF relay" +} + +strfry_setup() { + if [ -e "$STRFRY_CONF" ]; then + echo "strfry conf $STRFRY_CONF already exists" + return 0 + fi + + _create_dir "$STRFRY_DIR" "0700" || return "$?" + + cp "$TRADITIONAL_DIR/templates/strfry.conf" "$STRFRY_CONF" + + sed -i "s|\$STRFRY_DIR|$STRFRY_DIR|g" "$STRFRY_CONF" + sed -i "s/\$STRFRY_PORT/$STRFRY_PORT/g" "$STRFRY_CONF" + + echo "strfry directory set up" +} + +postgres_action() { + if [ "$#" -lt 1 ]; then + echo "error: insert postgres action" >&2 + return 1 + fi + action="$1" + shift 1 + case "$action" in + setup|database) ;; + *) + echo "error: wrong action" >&2 + return 1 + ;; + esac + + if ! _command_exist postgres; then + return 1 + fi + if ! _command_exist initdb; then + return 1 + fi + if ! _command_exist psql; then + return 1 + fi + + case "$action" in + setup) + if [ -e "$POSTGRES_DIR" ]; then + echo "postgres directory $POSTGRES_DIR already exists" + return 0 + fi + _create_dir "$POSTGRES_DIR" "0700" || return "$?" + + if ! initdb -D "$POSTGRES_DIR"; then + echo "error: running initdb" >&2 + return 1 + fi + + cat << EOF > "$POSTGRES_DIR/postgresql.conf" +port = $POSTGRES_PORT +unix_socket_directories = '$POSTGRES_DIR' +EOF + ;; + database) + if [ ! -d "$POSTGRES_DIR" ]; then + printf "%s%s\n" \ + "error: $POSTGRES_DIR is not a directory, " \ + "should run postgres-setup" \ + >&2 + return 1 + fi + ;; + esac + + postgres_setup_log_file="$TRADITIONAL_LOGS_DIR/postgres-setup-log" + echo "starting postgres, setup log file is $postgres_setup_log_file" + postgres -D "$POSTGRES_DIR" >>"$postgres_setup_log_file" 2>&1 & + postgres_pid="$!" + + _postgres_shut_down() { + echo "shutting down postgres" + if ! kill "$postgres_pid"; then + echo "error: shutting down postgres" >&2 + return 1 + fi + } + + echo "wait..." + sleep 5 + + case "$action" in + setup) + echo "setting up postgres user $POSTGRES_USER" + psql_stdin=$(cat << EOF +CREATE ROLE $POSTGRES_USER WITH LOGIN PASSWORD '$POSTGRES_PASS'; +ALTER ROLE $POSTGRES_USER CREATEDB; +EOF + ) + ;; + database) + psql_stdin=$(cat << EOF +CREATE DATABASE $POSTGRES_DB OWNER $POSTGRES_USER; +EOF + ) + ;; + esac + printf "%s\n" "$psql_stdin" | + psql -h localhost -p "$POSTGRES_PORT" -U "$USER" -d postgres + + echo "wait..." + sleep 5 + + case "$action" in + database) + if ! DJANGO_SUPERUSER_USERNAME="$(_get_env_var "ESCROW_USERNAME")"; then + _postgres_shut_down || return "$?" + return 1 + fi + + if ! python3 manage.py migrate; then + _postgres_shut_down || return "$?" + return 1 + fi + + # shellcheck disable=SC2034 + DJANGO_SUPERUSER_PASSWORD="password" + DJANGO_SUPERUSER_EMAIL="superuser@email.com" + if ! python3 manage.py createsuperuser \ + --noinput \ + --username "$DJANGO_SUPERUSER_USERNAME" \ + --email "$DJANGO_SUPERUSER_EMAIL" + then + _postgres_shut_down || return "$?" + return 1 + fi + ;; + esac + + _postgres_shut_down || return "$?" + + return 0 +} + +cleanup_signal() { + printf "\n" + printf "%s\n" "Caught $1 signal, sending it to services..." + + pkill -"$2" -f "$STRFRY_RELAY_COMMAND" + pkill -"$2" -f "$CELERY_BEAT_COMMAND" + pkill -"$2" -f "$CELERY_DEV_COMMAND" + pkill -"$2" -f "$FOLLOW_INVOICES_COMMAND" + # pkill -"$2" -f "$TELEGRAM_WATCHER_COMMAND" + pkill -"$2" -f "$CLEAN_ORDERS_COMMAND" + pkill -"$2" -f "$RUNSERVER_COMMAND" + pkill -"$2" -f "redis-server \*:${REDIS_PORT}" + pkill -"$2" -f "postgres -D $POSTGRES_DIR" + + exit 0 +} + +cleanup_int() { + printf "\n" + printf "%s\n" "Caught INT signal, shutting down services..." + + pkill -TERM -f "$STRFRY_RELAY_COMMAND" + pkill -INT -f "$CELERY_BEAT_COMMAND" + pkill -INT -f "$CELERY_DEV_COMMAND" + pkill -TERM -f "$FOLLOW_INVOICES_COMMAND" + # pkill -TERM -f "$TELEGRAM_WATCHER_COMMAND" + pkill -TERM -f "$CLEAN_ORDERS_COMMAND" + pkill -TERM -f "$RUNSERVER_COMMAND" + pkill -INT -f "redis-server \*:${REDIS_PORT}" + pkill -INT -f "postgres -D $POSTGRES_DIR" + + exit 0 +} + +main_loop() { + if [ "$#" -lt 1 ]; then + echo "error: insert main loop action" >&2 + return 1 + fi + action="$1" + shift 1 + case "$action" in + test|server) ;; + *) + echo "error: $1 is invalid" >&2 + return 1 + ;; + esac + + if ! _command_exist postgres; then + return 1 + fi + if ! _command_exist redis-server; then + return 1 + fi + if [ "$action" = "server" ]; then + if ! _command_exist celery; then + return 1 + fi + fi + + if [ ! -d "$POSTGRES_DIR" ]; then + printf "%s%s\n" \ + "error: $POSTGRES_DIR is not a directory, " \ + "should run postgres-setup and postgres-database" \ + >&2 + return 1 + fi + if [ "$action" = "server" ]; then + if [ ! -d "$STRFRY_DIR" ]; then + printf "%s%s\n" \ + "error: $STRFRY_DIR is not a directory, " \ + "should run setup" \ + >&2 + return 1 + fi + fi + + if ! pgrep -a bitcoind >/dev/null 2>&1 || { + ! pgrep -a lightningd >/dev/null 2>&1 && + ! pgrep -a lnd >/dev/null 2>&1 + }; then + printf "%s%s\n" \ + "error: bitcoin or lightning not running, " \ + "make sure to run this script after running regtest-nodes" \ + >&2 + return 1 + fi + + _create_dir "$REDIS_DIR" || return "$?" + _create_dir "$GNUPG_DIR" "0700" || return "$?" + + trap "cleanup_signal HUP" HUP + trap "cleanup_signal QUIT" QUIT + trap "cleanup_signal TERM" TERM + trap "cleanup_int" INT + + while true; do + if ! pgrep -f "postgres -D $POSTGRES_DIR" >/dev/null; then + echo "starting postgres" + postgres -D "$POSTGRES_DIR" >> "$TRADITIONAL_LOGS_DIR/postgres" 2>&1 & + fi + + if ! pgrep -f "redis-server \*:${REDIS_PORT}" >/dev/null; then + echo "starting redis" + printf "%s\n%s\n%s\n" \ + "dir $REDIS_DIR" \ + "port $REDIS_PORT" \ + "maxclients 1024" | + redis-server - >> "$TRADITIONAL_LOGS_DIR/redis" 2>&1 & + fi + + if [ "$action" = "server" ]; then + if ! pgrep -f "$RUNSERVER_COMMAND" >/dev/null; then + echo "starting runserver" + $RUNSERVER_COMMAND \ + >> "$TRADITIONAL_LOGS_DIR/runserver" 2>&1 & + fi + + if ! pgrep -f "$STRFRY_RELAY_COMMAND" >/dev/null; then + echo "starting strfry relay" + $STRFRY_RELAY_COMMAND \ + >> "$TRADITIONAL_LOGS_DIR/strfry-relay" 2>&1 & + fi + + if ! pgrep -f "$CLEAN_ORDERS_COMMAND" >/dev/null; then + echo "starting clean-orders" + $CLEAN_ORDERS_COMMAND \ + >> "$TRADITIONAL_LOGS_DIR/clean-orders" 2>&1 & + fi + + if ! pgrep -f "$FOLLOW_INVOICES_COMMAND" >/dev/null; then + echo "starting follow-invoices" + $FOLLOW_INVOICES_COMMAND \ + >> "$TRADITIONAL_LOGS_DIR/follow-invoices" 2>&1 & + fi + + # if _get_env_var "TELEGRAM_TOKEN" >/dev/null 2>&1; then + # if ! pgrep -f "$TELEGRAM_WATCHER_COMMAND" >/dev/null; then + # echo "starting telegram-watcher" + # $TELEGRAM_WATCHER_COMMAND \ + # >> "$TRADITIONAL_LOGS_DIR/telegram-watcher" 2>&1 & + # fi + # fi + + if ! pgrep -f "$CELERY_DEV_COMMAND" >/dev/null; then + echo "starting celery worker" + $CELERY_DEV_COMMAND >> "$TRADITIONAL_LOGS_DIR/celery-worker" 2>&1 & + fi + + if ! pgrep -f "$CELERY_BEAT_COMMAND" >/dev/null; then + echo "starting celery beat" + $CELERY_BEAT_COMMAND >> "$TRADITIONAL_LOGS_DIR/celery-beat" 2>&1 & + fi + fi + + sleep 2 + done +} + +_services_main() { + if [ "$#" -lt 1 ]; then + echo "error: insert action" >&2 + return 1 + fi + action="$1" + shift 1 + + if [ ! -f ".env" ]; then + echo "error: .env is not present" >&2 + return 1 + fi + if ! _command_exist dotenv; then + return 1 + fi + + case "$action" in + -h|--help) + cat << EOF +traditional-services action + +postgres-setup +postgres-database +strfry-setup +nginx-setup +test +server +EOF + return 0 + ;; + esac + + _services_environment_set || return "$?" + + case "$action" in + postgres-setup) + postgres_action "setup" + ;; + postgres-database) + postgres_action "database" + ;; + strfry-setup) + strfry_setup + ;; + test|server) + main_loop "$action" + ;; + *) + echo "error: action $action not recognized" >&2 + return 1 + ;; + esac +} + +_services_main "$@" diff --git a/setup.md b/setup.md index 09b6bd8a..2c79dec0 100644 --- a/setup.md +++ b/setup.md @@ -103,3 +103,9 @@ You will need these commands also often or eventually: `docker exec -it lnd-dev lncli -network=testnet payinvoice --allow_self_payment` **RoboSats development site should be accessible on 127.0.0.1:8000** + +# Backend Development + +## Traditional environment without docker + +See [scripts/traditional/README.md](scripts/traditional/README.md) diff --git a/tests/test_frontend_fetch.py b/tests/test_frontend_fetch.py index 08b68b2d..a52fded0 100644 --- a/tests/test_frontend_fetch.py +++ b/tests/test_frontend_fetch.py @@ -1,7 +1,12 @@ +import unittest +from decouple import config from django.test import Client, TestCase from django.urls import reverse +SKIP_FRONTEND_TESTS = config('SKIP_FRONTEND_TESTS', default=False, cast=bool) + +@unittest.skipIf(SKIP_FRONTEND_TESTS, "Skipping frontend tests") class FrontendFetchTest(TestCase): def setUp(self): self.client = Client() diff --git a/tests/utils/node.py b/tests/utils/node.py index 002de9bc..a30c7b9f 100644 --- a/tests/utils/node.py +++ b/tests/utils/node.py @@ -16,17 +16,24 @@ def get_node(name="robot"): We have two regtest LND nodes: "coordinator" (the robosats backend) and "robot" (the robosats user) """ if name == "robot": - macaroon = codecs.encode( - open("/lndrobot/data/chain/bitcoin/regtest/admin.macaroon", "rb").read(), - "hex", + admin_macaroon_file = config( + "LND_TEST_USER_MACAROON_PATH", cast=str, + default="/lndrobot/data/chain/bitcoin/regtest/admin.macaroon" ) - port = 8080 + macaroon = codecs.encode( + open(admin_macaroon_file, "rb").read(), "hex", + ) + port = config("LND_TEST_USER_REST_PORT", cast=int, default=8080) elif name == "coordinator": - macaroon = codecs.encode( - open("/lnd/data/chain/bitcoin/regtest/admin.macaroon", "rb").read(), "hex" + admin_macaroon_file = config( + "LND_TEST_COORD_MACAROON_PATH", cast=str, + default="/lnd/data/chain/bitcoin/regtest/admin.macaroon" ) - port = 8081 + macaroon = codecs.encode( + open(admin_macaroon_file, "rb").read(), "hex" + ) + port = config("LND_TEST_COORD_REST_PORT", cast=int, default=8081) return {"port": port, "headers": {"Grpc-Metadata-macaroon": macaroon}} @@ -158,10 +165,10 @@ def set_up_regtest_network(): # Coordinator is either LND or CLN. Robot user is always LND. if LNVENDOR == "LND": coordinator_node_id = get_lnd_node_id("coordinator") - coordinator_port = 9735 + coordinator_port = config("LND_TEST_COORD_LISTEN_PORT", cast=int, default=9735) elif LNVENDOR == "CLN": coordinator_node_id = get_cln_node_id() - coordinator_port = 9737 + coordinator_port = config("CLN_TEST_COORD_LISTEN_PORT", cast=int, default=9737) print("Coordinator Node ID: ", coordinator_node_id) @@ -258,8 +265,12 @@ def generate_blocks(address, num_blocks): "method": "generatetoaddress", "params": [num_blocks, address], } + # set in docker-tests.yml + rpc_url = config("BITCOIND_RPCURL", cast=str, default="http://localhost:18443") + rpc_user = config("BITCOIND_RPCUSER", cast=str, default="test") + rpc_pass = config("BITCOIND_RPCPASSWORD", cast=str, default="test") response = requests.post( - "http://localhost:18443", json=data, auth=HTTPBasicAuth("test", "test") + rpc_url, json=data, auth=HTTPBasicAuth(rpc_user, rpc_pass) ) return response.json() diff --git a/tests/utils/pgp.py b/tests/utils/pgp.py index 7150c64f..61501603 100644 --- a/tests/utils/pgp.py +++ b/tests/utils/pgp.py @@ -1,8 +1,9 @@ +from decouple import config import gnupg def sign_message(message, private_key_path, passphrase_path): - gpg = gnupg.GPG() + gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None)) with open(private_key_path, "r") as f: private_key = f.read()