From 50569e275f9ff5f9e38c425729b5a1e3f3fe667f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 04:56:31 +0000 Subject: [PATCH 01/77] chore(deps): update dependency wait-on to v9.0.1 (#1281) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 5c6e5ac0c8..aa4fe1e2a2 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "ts-node": "10.9.2", "typescript": "5.5.4", "utf-8-validate": "6.0.5", - "wait-on": "9.0.0", + "wait-on": "9.0.1", "webpack": "4.44.2", "ws": "8.18.3" }, diff --git a/yarn.lock b/yarn.lock index 23f2638314..dce6bf1982 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4772,10 +4772,10 @@ axe-core@=4.7.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axios@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.12.1.tgz#0747b39c5b615f81f93f2c138e6d82a71426937f" - integrity sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ== +axios@^1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.12.2.tgz#6c307390136cf7a2278d09cec63b136dfc6e6da7" + integrity sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.4" @@ -20716,12 +20716,12 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" -wait-on@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-9.0.0.tgz#583e2ab560b71ce6247f422a9857122b34cfd893" - integrity sha512-bKOl7CJ4zGhKW4qvoasLM5t2NtLUcc1Ar2N6XeYCQpW0w+DMdLC0YH1JUH3bTWDCsHblapHMzhtFmmPc+ITNJw== +wait-on@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-9.0.1.tgz#c5f2c3094b8e808a241cf41d2aaecd4f762907ec" + integrity sha512-noeCAI+XbqWMXY23sKril0BSURhuLYarkVXwJv1uUWwoojZJE7pmX3vJ7kh7SZaNgPGzfsCSQIZM/AGvu0Q9pA== dependencies: - axios "^1.12.1" + axios "^1.12.2" joi "^18.0.1" lodash "^4.17.21" minimist "^1.2.8" From d637ff209c67163da92d7178ab7dbe7ddd3dcbc4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:34:55 +0000 Subject: [PATCH 02/77] chore(deps): update dependency @types/dockerode to v3.3.44 (#1280) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aa4fe1e2a2..a865c72e1d 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@testing-library/user-event": "14.6.1", "@types/archiver": "6.0.3", "@types/detect-port": "1.3.5", - "@types/dockerode": "3.3.43", + "@types/dockerode": "3.3.44", "@types/fs-extra": "9.0.13", "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", diff --git a/yarn.lock b/yarn.lock index dce6bf1982..b9948e1983 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3078,10 +3078,10 @@ "@types/node" "*" "@types/ssh2" "*" -"@types/dockerode@3.3.43": - version "3.3.43" - resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.43.tgz#df63180efa8cc910720c778b729548817afe3de8" - integrity sha512-YCi0aKKpKeC9dhKTbuglvsWDnAyuIITd6CCJSTKiAdbDzPH4RWu0P9IK2XkJHdyplH6mzYtDYO+gB06JlzcPxg== +"@types/dockerode@3.3.44": + version "3.3.44" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.44.tgz#1e6d5b291646820e9daabfa132cdb33c9d535b56" + integrity sha512-fUpIHlsbYpxAJb285xx3vp7q5wf5mjqSn3cYwl/MhiM+DB99OdO5sOCPlO0PjO+TyOtphPs7tMVLU/RtOo/JjA== dependencies: "@types/docker-modem" "*" "@types/node" "*" From 4b8fed1ad828d240c4e5010482aecf930b4f25f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:26:18 +0000 Subject: [PATCH 03/77] chore(deps): update dependency lint-staged to v16.2.0 (#1282) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 133 +++++++++++++++++++++++---------------------------- 2 files changed, 61 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index a865c72e1d..2b8bb78c16 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.0", "less-loader": "12.3.0", - "lint-staged": "16.1.6", + "lint-staged": "16.2.0", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.0", diff --git a/yarn.lock b/yarn.lock index b9948e1983..d4a8952a45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4161,7 +4161,7 @@ ansi-styles@^5.0.0, ansi-styles@^5.2.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: +ansi-styles@^6.1.0, ansi-styles@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== @@ -5766,11 +5766,6 @@ chalk@^5.3.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chalk@^5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.0.tgz#a1a8d294ea3526dbb77660f12649a08490e33ab8" - integrity sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ== - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -5957,13 +5952,13 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-truncate@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" - integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== +cli-truncate@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-5.1.0.tgz#bb12607a62f0e4bb91a54aa4653b23347900bb55" + integrity sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g== dependencies: - slice-ansi "^5.0.0" - string-width "^7.0.0" + slice-ansi "^7.1.0" + string-width "^8.0.0" cli-width@^2.0.0: version "2.2.1" @@ -6136,16 +6131,16 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.1.tgz#2f9225c19e6ebd0dc4404dd45821b2caa17ea09b" + integrity sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A== + commander@2.11.x: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== -commander@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.0.tgz#f244fc74a92343514e56229f16ef5c5e22ced5e9" - integrity sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== - commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -9915,6 +9910,11 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== +get-east-asian-width@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz#9bc4caa131702b4b61729cb7e42735bc550c9ee6" + integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q== + get-func-name@^2.0.0, get-func-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" @@ -11595,11 +11595,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - is-fullwidth-code-point@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" @@ -13195,31 +13190,23 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" -lilconfig@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" - integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.1.6: - version "16.1.6" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.1.6.tgz#b0830df339a71f4207979a47c7be8ab0f38543ad" - integrity sha512-U4kuulU3CKIytlkLlaHcGgKscNfJPNTiDF2avIUGFCv7K95/DCYQ7Ra62ydeRWmgQGg9zJYw2dzdbztwJlqrow== +lint-staged@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.0.tgz#ea7157bf007bdb50d2bb0559bc91c8e77d71c84b" + integrity sha512-spdYSOCQ2MdZ9CM1/bu/kDmaYGsrpNOeu1InFFV8uhv14x6YIubGxbCpSmGILFoxkiheNQPDXSg5Sbb5ZuVnug== dependencies: - chalk "^5.6.0" - commander "^14.0.0" - debug "^4.4.1" - lilconfig "^3.1.3" - listr2 "^9.0.3" - micromatch "^4.0.8" - nano-spawn "^1.0.2" - pidtree "^0.6.0" - string-argv "^0.3.2" - yaml "^2.8.1" + commander "14.0.1" + listr2 "9.0.4" + micromatch "4.0.8" + nano-spawn "1.0.3" + pidtree "0.6.0" + string-argv "0.3.2" + yaml "2.8.1" linux-platform-info@^0.0.3: version "0.0.3" @@ -13228,12 +13215,12 @@ linux-platform-info@^0.0.3: dependencies: os-family "^1.0.0" -listr2@^9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.3.tgz#5181284019e1d577dc2d705ca6d3a148cf15adf3" - integrity sha512-0aeh5HHHgmq1KRdMMDHfhMWQmIT/m7nRDTlxlFqni2Sp0had9baqsjJRvDGdlvgd6NmPE0nPloOipiQJGFtTHQ== +listr2@9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.4.tgz#2916e633ae6e09d1a3f981172937ac1c5a8fa64f" + integrity sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ== dependencies: - cli-truncate "^4.0.0" + cli-truncate "^5.0.0" colorette "^2.0.20" eventemitter3 "^5.0.1" log-update "^6.1.0" @@ -13753,6 +13740,14 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== +micromatch@4.0.8, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -13780,14 +13775,6 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -micromatch@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -14110,10 +14097,10 @@ nan@^2.12.1, nan@^2.14.0, nan@^2.17.0, nan@^2.18.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== -nano-spawn@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.2.tgz#9853795681f0e96ef6f39104c2e4347b6ba79bf6" - integrity sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg== +nano-spawn@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.3.tgz#ef8d89a275eebc8657e67b95fc312a6527a05b8d" + integrity sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA== nanoid@^3.1.12, nanoid@^3.1.31, nanoid@^3.3.7: version "3.3.7" @@ -15109,7 +15096,7 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pidtree@^0.6.0: +pidtree@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== @@ -18305,14 +18292,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slice-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" - integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== - dependencies: - ansi-styles "^6.0.0" - is-fullwidth-code-point "^4.0.0" - slice-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" @@ -18750,7 +18729,7 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -string-argv@^0.3.2: +string-argv@0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== @@ -18826,6 +18805,14 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" +string-width@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.1.0.tgz#9e9fb305174947cf45c30529414b5da916e9e8d1" + integrity sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg== + dependencies: + get-east-asian-width "^1.3.0" + strip-ansi "^7.1.0" + string.prototype.matchall@^4.0.12: version "4.0.12" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" @@ -21428,6 +21415,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" @@ -21438,11 +21430,6 @@ yaml@^2.2.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.3.tgz#0777516b8c7880bcaa0f426a5410e8d6b0be1f3d" integrity sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg== -yaml@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" - integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== - yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" From 7ee3aa5f0de4d0d4b0ccb8b119dffba0ea82cf8b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 17:39:31 +0000 Subject: [PATCH 04/77] chore(deps): update commitlint monorepo to v20 (#1283) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- yarn.lock | 192 +++++++++++++++++++++++++-------------------------- 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/package.json b/package.json index 2b8bb78c16..77d2738a1d 100644 --- a/package.json +++ b/package.json @@ -65,8 +65,8 @@ "devDependencies": { "@ant-design/icons": "5.6.1", "@babel/plugin-proposal-private-property-in-object": "7.21.11", - "@commitlint/cli": "19.8.1", - "@commitlint/config-conventional": "19.8.1", + "@commitlint/cli": "20.0.0", + "@commitlint/config-conventional": "20.0.0", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", "@emotion/styled": "11.14.1", diff --git a/yarn.lock b/yarn.lock index d4a8952a45..8b49eef3d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1526,25 +1526,25 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@commitlint/cli@19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.8.1.tgz#85f7d9f331344e1f0a2b9d8b24fd3695466e1158" - integrity sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA== - dependencies: - "@commitlint/format" "^19.8.1" - "@commitlint/lint" "^19.8.1" - "@commitlint/load" "^19.8.1" - "@commitlint/read" "^19.8.1" - "@commitlint/types" "^19.8.1" +"@commitlint/cli@20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-20.0.0.tgz#9459cbf4c0cbabca19bc7219ad295f7f39791e4f" + integrity sha512-I3D7Yldq8ZhOB3qEaTvXWIgib6tSZhbCpRObfFQ/aYI0J9AH8NMwT07Ak+bpE3n6Yn7EtbqEhQUkJZ/jZ5kCeQ== + dependencies: + "@commitlint/format" "^20.0.0" + "@commitlint/lint" "^20.0.0" + "@commitlint/load" "^20.0.0" + "@commitlint/read" "^20.0.0" + "@commitlint/types" "^20.0.0" tinyexec "^1.0.0" yargs "^17.0.0" -"@commitlint/config-conventional@19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz#eab42df58cda44f18410ae0cbd6785ece00f214b" - integrity sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ== +"@commitlint/config-conventional@20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-20.0.0.tgz#f222dc9ce08e16f9c66eae55e99129d2be517546" + integrity sha512-q7JroPIkDBtyOkVe9Bca0p7kAUYxZMxkrBArCfuD3yN4KjRAenP9PmYwnn7rsw8Q+hHq1QB2BRmBh0/Z19ZoJw== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" conventional-changelog-conventionalcommits "^7.0.2" "@commitlint/config-validator@^18.4.4": @@ -1555,20 +1555,20 @@ "@commitlint/types" "^18.4.4" ajv "^8.11.0" -"@commitlint/config-validator@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-19.8.1.tgz#29e9bb1360fa41b9439b23d8e25deaaf097306b5" - integrity sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ== +"@commitlint/config-validator@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-20.0.0.tgz#d97d83be722a04be2038e54bdd3ec7d11efec557" + integrity sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" ajv "^8.11.0" -"@commitlint/ensure@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-19.8.1.tgz#938c54d6f586bda600b5c8e8e842edb281546e14" - integrity sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw== +"@commitlint/ensure@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-20.0.0.tgz#f97c16f53c0f7ea79895f9a19e5dad5213353aef" + integrity sha512-WBV47Fffvabe68n+13HJNFBqiMH5U1Ryls4W3ieGwPC0C7kJqp3OVQQzG2GXqOALmzrgAB+7GXmyy8N9ct8/Fg== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" lodash.camelcase "^4.3.0" lodash.kebabcase "^4.1.1" lodash.snakecase "^4.1.1" @@ -1580,36 +1580,36 @@ resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-18.4.4.tgz#ade986742c1944c8162a54288747e54a8c6146b5" integrity sha512-a37Nd3bDQydtg9PCLLWM9ZC+GO7X5i4zJvrggJv5jBhaHsXeQ9ZWdO6ODYR+f0LxBXXNYK3geYXJrCWUCP8JEg== -"@commitlint/execute-rule@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz#53000363b737773e2d25e97c20f15eaa78742067" - integrity sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA== +"@commitlint/execute-rule@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz#013628e09179cf2d3c977e1cf37937b5cb869af8" + integrity sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw== -"@commitlint/format@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-19.8.1.tgz#3e09b1291b3e29092d7a86f0afbbcfc0d99d3ad4" - integrity sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw== +"@commitlint/format@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-20.0.0.tgz#46c9c032bb02511f4a88d82460d036bd555a1940" + integrity sha512-zrZQXUcSDmQ4eGGrd+gFESiX0Rw+WFJk7nW4VFOmxub4mAATNKBQ4vNw5FgMCVehLUKG2OT2LjOqD0Hk8HvcRg== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" chalk "^5.3.0" -"@commitlint/is-ignored@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz#fed0851360ea2d21799eaf8ec9ef6d98c15536e3" - integrity sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg== +"@commitlint/is-ignored@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-20.0.0.tgz#80157d00985e698364d92bc63bf5bb2730a0c7d2" + integrity sha512-ayPLicsqqGAphYIQwh9LdAYOVAQ9Oe5QCgTNTj+BfxZb9b/JW222V5taPoIBzYnAP0z9EfUtljgBk+0BN4T4Cw== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" semver "^7.6.0" -"@commitlint/lint@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.8.1.tgz#c21bf9000ca54e41c5b0139c98aaf12473c03bb0" - integrity sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw== +"@commitlint/lint@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-20.0.0.tgz#3f61ebb1c7c69b82ad3f43cfcf91ce318b1a5c3a" + integrity sha512-kWrX8SfWk4+4nCexfLaQT3f3EcNjJwJBsSZ5rMBw6JCd6OzXufFHgel2Curos4LKIxwec9WSvs2YUD87rXlxNQ== dependencies: - "@commitlint/is-ignored" "^19.8.1" - "@commitlint/parse" "^19.8.1" - "@commitlint/rules" "^19.8.1" - "@commitlint/types" "^19.8.1" + "@commitlint/is-ignored" "^20.0.0" + "@commitlint/parse" "^20.0.0" + "@commitlint/rules" "^20.0.0" + "@commitlint/types" "^20.0.0" "@commitlint/load@>6.1.1": version "18.4.4" @@ -1628,15 +1628,15 @@ lodash.uniq "^4.5.0" resolve-from "^5.0.0" -"@commitlint/load@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.8.1.tgz#b997b1f65a961bf0a47189f15f6dc8786ceb4576" - integrity sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A== +"@commitlint/load@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-20.0.0.tgz#13fc910cc5f6d2325d499886d95fca797791de7c" + integrity sha512-WiNKO9fDPlLY90Rruw2HqHKcghrmj5+kMDJ4GcTlX1weL8K07Q6b27C179DxnsrjGCRAKVwFKyzxV4x+xDY28Q== dependencies: - "@commitlint/config-validator" "^19.8.1" - "@commitlint/execute-rule" "^19.8.1" - "@commitlint/resolve-extends" "^19.8.1" - "@commitlint/types" "^19.8.1" + "@commitlint/config-validator" "^20.0.0" + "@commitlint/execute-rule" "^20.0.0" + "@commitlint/resolve-extends" "^20.0.0" + "@commitlint/types" "^20.0.0" chalk "^5.3.0" cosmiconfig "^9.0.0" cosmiconfig-typescript-loader "^6.1.0" @@ -1644,27 +1644,27 @@ lodash.merge "^4.6.2" lodash.uniq "^4.5.0" -"@commitlint/message@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-19.8.1.tgz#d5d0d87837483d9f9b4559ffa06e1aaa26d266d6" - integrity sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg== +"@commitlint/message@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-20.0.0.tgz#a5ac95dc17363a1dba5d2d47bd28c9356710a7b8" + integrity sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ== -"@commitlint/parse@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-19.8.1.tgz#73125d04f07f11477cf563cbfe0cc9f6dc85a747" - integrity sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw== +"@commitlint/parse@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-20.0.0.tgz#a056ec3c25401dfc9905196e159aaee3a2dfdf43" + integrity sha512-j/PHCDX2bGM5xGcWObOvpOc54cXjn9g6xScXzAeOLwTsScaL4Y+qd0pFC6HBwTtrH92NvJQc+2Lx9HFkVi48cg== dependencies: - "@commitlint/types" "^19.8.1" + "@commitlint/types" "^20.0.0" conventional-changelog-angular "^7.0.0" conventional-commits-parser "^5.0.0" -"@commitlint/read@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-19.8.1.tgz#812930fd0f616e796e122751cb983346e5454ec8" - integrity sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ== +"@commitlint/read@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-20.0.0.tgz#6c22541109176878d533c396860d26ad8ec3d74f" + integrity sha512-Ti7Y7aEgxsM1nkwA4ZIJczkTFRX/+USMjNrL9NXwWQHqNqrBX2iMi+zfuzZXqfZ327WXBjdkRaytJ+z5vNqTOA== dependencies: - "@commitlint/top-level" "^19.8.1" - "@commitlint/types" "^19.8.1" + "@commitlint/top-level" "^20.0.0" + "@commitlint/types" "^20.0.0" git-raw-commits "^4.0.0" minimist "^1.2.8" tinyexec "^1.0.0" @@ -1681,37 +1681,37 @@ resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/resolve-extends@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz#a44bb4c22e3e7d407cc9a3758fcf58f5c360b694" - integrity sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg== +"@commitlint/resolve-extends@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-20.0.0.tgz#a92e370b67b9a99aec84904fbb4e5fcaa495ee73" + integrity sha512-BA4vva1hY8y0/Hl80YDhe9TJZpRFMsUYzVxvwTLPTEBotbGx/gS49JlVvtF1tOCKODQp7pS7CbxCpiceBgp3Dg== dependencies: - "@commitlint/config-validator" "^19.8.1" - "@commitlint/types" "^19.8.1" + "@commitlint/config-validator" "^20.0.0" + "@commitlint/types" "^20.0.0" global-directory "^4.0.1" import-meta-resolve "^4.0.0" lodash.mergewith "^4.6.2" resolve-from "^5.0.0" -"@commitlint/rules@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-19.8.1.tgz#1cea53d5bf970ce56dc105e1da5e6655a2fe7a5f" - integrity sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw== +"@commitlint/rules@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-20.0.0.tgz#d5793a9435313182477456a317822874232b7d0f" + integrity sha512-gvg2k10I/RfvHn5I5sxvVZKM1fl72Sqrv2YY/BnM7lMHcYqO0E2jnRWoYguvBfEcZ39t+rbATlciggVe77E4zA== dependencies: - "@commitlint/ensure" "^19.8.1" - "@commitlint/message" "^19.8.1" - "@commitlint/to-lines" "^19.8.1" - "@commitlint/types" "^19.8.1" + "@commitlint/ensure" "^20.0.0" + "@commitlint/message" "^20.0.0" + "@commitlint/to-lines" "^20.0.0" + "@commitlint/types" "^20.0.0" -"@commitlint/to-lines@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-19.8.1.tgz#c1a28a84542c7ba321c1c11178b83ae024257b47" - integrity sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg== +"@commitlint/to-lines@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-20.0.0.tgz#0f6d6106016272ef0e9f7c138093fe2cc06fc34b" + integrity sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw== -"@commitlint/top-level@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-19.8.1.tgz#2c942189d83a29b21ff7ba6e91607301efdf5916" - integrity sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw== +"@commitlint/top-level@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-20.0.0.tgz#8c8929d2de4639c621d63ea27b9900fc7ad8a121" + integrity sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg== dependencies: find-up "^7.0.0" @@ -1722,10 +1722,10 @@ dependencies: chalk "^4.1.0" -"@commitlint/types@^19.8.1": - version "19.8.1" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-19.8.1.tgz#7971fbd56b0cfb31692a4e1941b74ac8217c44e5" - integrity sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw== +"@commitlint/types@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-20.0.0.tgz#70edef6e1c1d3aaca15e1e87242d8d256beebe67" + integrity sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA== dependencies: "@types/conventional-commits-parser" "^5.0.0" chalk "^5.3.0" From a38ee615a6daf0da4d5074ad989fcde5a7327c60 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Sep 2025 05:47:52 +0000 Subject: [PATCH 05/77] chore(deps): update eclipse-temurin docker tag to v25 (#1286) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/eclair/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/eclair/Dockerfile b/docker/eclair/Dockerfile index 4c64ca8764..7307abcd53 100644 --- a/docker/eclair/Dockerfile +++ b/docker/eclair/Dockerfile @@ -1,7 +1,7 @@ ######################### # Original Source: https://github.com/ACINQ/eclair/blob/v0.12.0/Dockerfile ######################### -FROM eclipse-temurin:21.0.8_9-jdk-alpine as BUILD +FROM eclipse-temurin:25-jdk-alpine as BUILD # Let's fetch eclair dependencies, so that Docker can cache them # This way we won't have to fetch dependencies again if only the source code changes @@ -55,7 +55,7 @@ RUN cp -R -f /usr/repo/* . RUN ./mvnw package -pl eclair-node -am -DskipTests -Dgit.commit.id=notag -Dgit.commit.id.abbrev=notag -o # It might be good idea to run the tests here, so that the docker build fail if the code is bugged -FROM eclipse-temurin:21.0.8_9-jre-alpine +FROM eclipse-temurin:25-jre-alpine WORKDIR /app # install jq for eclair-cli From f22fc0300c95cf36a6ce21a5fb9909f535e4b389 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Sep 2025 08:23:22 +0000 Subject: [PATCH 06/77] chore(deps): update dependency lint-staged to v16.2.1 (#1284) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 66 ++++++++++++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 77d2738a1d..e77d72b0d3 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.0", "less-loader": "12.3.0", - "lint-staged": "16.2.0", + "lint-staged": "16.2.1", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.0", diff --git a/yarn.lock b/yarn.lock index 8b49eef3d9..a562cbe0f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6131,16 +6131,16 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.1.tgz#2f9225c19e6ebd0dc4404dd45821b2caa17ea09b" - integrity sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A== - commander@2.11.x: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== +commander@^14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.1.tgz#2f9225c19e6ebd0dc4404dd45821b2caa17ea09b" + integrity sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -13195,18 +13195,18 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.0.tgz#ea7157bf007bdb50d2bb0559bc91c8e77d71c84b" - integrity sha512-spdYSOCQ2MdZ9CM1/bu/kDmaYGsrpNOeu1InFFV8uhv14x6YIubGxbCpSmGILFoxkiheNQPDXSg5Sbb5ZuVnug== +lint-staged@16.2.1: + version "16.2.1" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.1.tgz#bb82da8ce10059296b220f321980f0ee1ce40c28" + integrity sha512-KMeYmH9wKvHsXdUp+z6w7HN3fHKHXwT1pSTQTYxB9kI6ekK1rlL3kLZEoXZCppRPXFK9PFW/wfQctV7XUqMrPQ== dependencies: - commander "14.0.1" - listr2 "9.0.4" - micromatch "4.0.8" - nano-spawn "1.0.3" - pidtree "0.6.0" - string-argv "0.3.2" - yaml "2.8.1" + commander "^14.0.1" + listr2 "^9.0.4" + micromatch "^4.0.8" + nano-spawn "^1.0.3" + pidtree "^0.6.0" + string-argv "^0.3.2" + yaml "^2.8.1" linux-platform-info@^0.0.3: version "0.0.3" @@ -13215,7 +13215,7 @@ linux-platform-info@^0.0.3: dependencies: os-family "^1.0.0" -listr2@9.0.4: +listr2@^9.0.4: version "9.0.4" resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.4.tgz#2916e633ae6e09d1a3f981172937ac1c5a8fa64f" integrity sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ== @@ -13740,14 +13740,6 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== -micromatch@4.0.8, micromatch@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -13775,6 +13767,14 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -14097,7 +14097,7 @@ nan@^2.12.1, nan@^2.14.0, nan@^2.17.0, nan@^2.18.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== -nano-spawn@1.0.3: +nano-spawn@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.3.tgz#ef8d89a275eebc8657e67b95fc312a6527a05b8d" integrity sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA== @@ -15096,7 +15096,7 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pidtree@0.6.0: +pidtree@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== @@ -18729,7 +18729,7 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -string-argv@0.3.2: +string-argv@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== @@ -21415,11 +21415,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" - integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== - yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" @@ -21430,6 +21425,11 @@ yaml@^2.2.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.3.tgz#0777516b8c7880bcaa0f426a5410e8d6b0be1f3d" integrity sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg== +yaml@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" From 072b7e0246747829fba1f7b76ad75c0dafebb790 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 20:35:49 +0000 Subject: [PATCH 07/77] chore(deps): update dependency lint-staged to v16.2.3 (#1287) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e77d72b0d3..bdbc92e162 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.0", "less-loader": "12.3.0", - "lint-staged": "16.2.1", + "lint-staged": "16.2.3", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.0", diff --git a/yarn.lock b/yarn.lock index a562cbe0f5..70127f5df7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13195,10 +13195,10 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.1: - version "16.2.1" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.1.tgz#bb82da8ce10059296b220f321980f0ee1ce40c28" - integrity sha512-KMeYmH9wKvHsXdUp+z6w7HN3fHKHXwT1pSTQTYxB9kI6ekK1rlL3kLZEoXZCppRPXFK9PFW/wfQctV7XUqMrPQ== +lint-staged@16.2.3: + version "16.2.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.3.tgz#790866221d75602510507b5be40b2c7963715960" + integrity sha512-1OnJEESB9zZqsp61XHH2fvpS1es3hRCxMplF/AJUDa8Ho8VrscYDIuxGrj3m8KPXbcWZ8fT9XTMUhEQmOVKpKw== dependencies: commander "^14.0.1" listr2 "^9.0.4" From 68e02ba8f701d656f51be256424901509bf42955 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 02:05:21 +0000 Subject: [PATCH 08/77] chore(deps): update dependency patch-package to v8.0.1 (#1288) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index bdbc92e162..7ece207580 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ "lint-staged": "16.2.3", "lndconnect": "0.2.10", "nodemon": "3.1.10", - "patch-package": "8.0.0", + "patch-package": "8.0.1", "prettier": "2.8.8", "react": "17.0.2", "react-async-hook": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 70127f5df7..20869da879 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14925,25 +14925,24 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== -patch-package@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" - integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== +patch-package@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.1.tgz#79d02f953f711e06d1f8949c8a13e5d3d7ba1a60" + integrity sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw== dependencies: "@yarnpkg/lockfile" "^1.1.0" chalk "^4.1.2" ci-info "^3.7.0" cross-spawn "^7.0.3" find-yarn-workspace-root "^2.0.0" - fs-extra "^9.0.0" + fs-extra "^10.0.0" json-stable-stringify "^1.0.2" klaw-sync "^6.0.0" minimist "^1.2.6" open "^7.4.2" - rimraf "^2.6.3" semver "^7.5.3" slash "^2.0.0" - tmp "^0.0.33" + tmp "^0.2.4" yaml "^2.2.2" path-browserify@0.0.1: @@ -19802,6 +19801,11 @@ tmp@^0.2.0: dependencies: rimraf "^3.0.0" +tmp@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" + integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" From a65efa5a01428f8950dd25ea17975c5929ed9c17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:12:59 +0000 Subject: [PATCH 09/77] chore(deps): update dependency cross-env to v10.1.0 (#1289) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7ece207580..89d0db9f1c 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "commitizen": "4.3.1", "concurrently": "9.2.1", "connected-react-router": "6.9.3", - "cross-env": "10.0.0", + "cross-env": "10.1.0", "detect-port": "1.6.1", "docker-compose": "0.24.0", "dockerode": "4.0.2", diff --git a/yarn.lock b/yarn.lock index 20869da879..f4a9ef92e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6774,10 +6774,10 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-env@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-10.0.0.tgz#ba25823cfa1ed6af293dcded8796fa16cd162456" - integrity sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q== +cross-env@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-10.1.0.tgz#cfd2a6200df9ed75bfb9cb3d7ce609c13ea21783" + integrity sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw== dependencies: "@epic-web/invariant" "^1.0.0" cross-spawn "^7.0.6" From 72572ce12bd0f623e2ca2c79605e7f5d85c72f20 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 05:31:33 +0000 Subject: [PATCH 10/77] chore(deps): update dependency @types/react to v18.3.25 (#1290) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 89d0db9f1c..5ee2d43d74 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", "@types/node": "18.17.19", - "@types/react": "18.3.24", + "@types/react": "18.3.25", "@types/react-copy-to-clipboard": "5.0.7", "@types/react-dom": "18.3.7", "@types/react-redux": "7.1.34", diff --git a/yarn.lock b/yarn.lock index f4a9ef92e1..67983a7417 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3352,10 +3352,10 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.3.24": - version "18.3.24" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.24.tgz#f6a5a4c613242dfe3af0dcee2b4ec47b92d9b6bd" - integrity sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A== +"@types/react@18.3.25": + version "18.3.25" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.25.tgz#b37e3b05b6762b49f3944760f3bce3d5b6afa19b" + integrity sha512-oSVZmGtDPmRZtVDqvdKUi/qgCsWp5IDY29wp8na8Bj4B3cc99hfNzvNhlMkVVxctkAOGUA3Km7MMpBHAnWfcIA== dependencies: "@types/prop-types" "*" csstype "^3.0.2" From fc549881dc64bf982052090b791096b8e96ef469 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 09:58:27 +0000 Subject: [PATCH 11/77] chore(deps): update dependency @commitlint/cli to v20.1.0 (#1291) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 5ee2d43d74..24289bce23 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@ant-design/icons": "5.6.1", "@babel/plugin-proposal-private-property-in-object": "7.21.11", - "@commitlint/cli": "20.0.0", + "@commitlint/cli": "20.1.0", "@commitlint/config-conventional": "20.0.0", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", diff --git a/yarn.lock b/yarn.lock index 67983a7417..6e18133762 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1526,14 +1526,14 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@commitlint/cli@20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-20.0.0.tgz#9459cbf4c0cbabca19bc7219ad295f7f39791e4f" - integrity sha512-I3D7Yldq8ZhOB3qEaTvXWIgib6tSZhbCpRObfFQ/aYI0J9AH8NMwT07Ak+bpE3n6Yn7EtbqEhQUkJZ/jZ5kCeQ== +"@commitlint/cli@20.1.0": + version "20.1.0" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-20.1.0.tgz#07365e2849d86f771e76ea0ceb96cd88bb945e03" + integrity sha512-pW5ujjrOovhq5RcYv5xCpb4GkZxkO2+GtOdBW2/qrr0Ll9tl3PX0aBBobGQl3mdZUbOBgwAexEQLeH6uxL0VYg== dependencies: "@commitlint/format" "^20.0.0" "@commitlint/lint" "^20.0.0" - "@commitlint/load" "^20.0.0" + "@commitlint/load" "^20.1.0" "@commitlint/read" "^20.0.0" "@commitlint/types" "^20.0.0" tinyexec "^1.0.0" @@ -1628,14 +1628,14 @@ lodash.uniq "^4.5.0" resolve-from "^5.0.0" -"@commitlint/load@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-20.0.0.tgz#13fc910cc5f6d2325d499886d95fca797791de7c" - integrity sha512-WiNKO9fDPlLY90Rruw2HqHKcghrmj5+kMDJ4GcTlX1weL8K07Q6b27C179DxnsrjGCRAKVwFKyzxV4x+xDY28Q== +"@commitlint/load@^20.1.0": + version "20.1.0" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-20.1.0.tgz#8eb7aefbfb066db903d1a89c4727093a57fcffbc" + integrity sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg== dependencies: "@commitlint/config-validator" "^20.0.0" "@commitlint/execute-rule" "^20.0.0" - "@commitlint/resolve-extends" "^20.0.0" + "@commitlint/resolve-extends" "^20.1.0" "@commitlint/types" "^20.0.0" chalk "^5.3.0" cosmiconfig "^9.0.0" @@ -1681,10 +1681,10 @@ resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/resolve-extends@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-20.0.0.tgz#a92e370b67b9a99aec84904fbb4e5fcaa495ee73" - integrity sha512-BA4vva1hY8y0/Hl80YDhe9TJZpRFMsUYzVxvwTLPTEBotbGx/gS49JlVvtF1tOCKODQp7pS7CbxCpiceBgp3Dg== +"@commitlint/resolve-extends@^20.1.0": + version "20.1.0" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-20.1.0.tgz#bfccbd7772ffa49f99f3e0f828cf8612667b2e8e" + integrity sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw== dependencies: "@commitlint/config-validator" "^20.0.0" "@commitlint/types" "^20.0.0" From 42dfb3c90275c07c0f273af2956bda8b6dce1e29 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 21:40:28 +0000 Subject: [PATCH 12/77] chore(deps): update dependency stylelint to v16.25.0 (#1293) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 24289bce23..f388fb302c 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "standard-version": "9.5.0", "strip-ansi": "6.0.1", "styled-components": "6.1.19", - "stylelint": "16.24.0", + "stylelint": "16.25.0", "stylelint-config-prettier": "9.0.5", "stylelint-config-standard": "39.0.0", "testcafe": "3.7.2", diff --git a/yarn.lock b/yarn.lock index 6e18133762..a8c878ecea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1798,10 +1798,10 @@ lodash "4.6.1 || ^4.16.1" pinkie-promise "^2.0.0" -"@dual-bundle/import-meta-resolve@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#519c1549b0e147759e7825701ecffd25e5819f7b" - integrity sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg== +"@dual-bundle/import-meta-resolve@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.2.1.tgz#cd0b25b3808cd9e684cd6cd549bbf8e1dcf05ee7" + integrity sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg== "@electron/asar@^3.2.1", "@electron/asar@^3.2.3": version "3.2.8" @@ -7259,10 +7259,10 @@ debug@^3.2.5, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" - integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" @@ -19112,22 +19112,22 @@ stylelint-config-standard@39.0.0: dependencies: stylelint-config-recommended "^17.0.0" -stylelint@16.24.0: - version "16.24.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.24.0.tgz#a436920636732b496a55665997f2804d1d63b5b6" - integrity sha512-7ksgz3zJaSbTUGr/ujMXvLVKdDhLbGl3R/3arNudH7z88+XZZGNLMTepsY28WlnvEFcuOmUe7fg40Q3lfhOfSQ== +stylelint@16.25.0: + version "16.25.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.25.0.tgz#c3d602974f2a18fa57fadc9f3f40129b098fe4dc" + integrity sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ== dependencies: "@csstools/css-parser-algorithms" "^3.0.5" "@csstools/css-tokenizer" "^3.0.4" "@csstools/media-query-list-parser" "^4.0.3" "@csstools/selector-specificity" "^5.0.0" - "@dual-bundle/import-meta-resolve" "^4.1.0" + "@dual-bundle/import-meta-resolve" "^4.2.1" balanced-match "^2.0.0" colord "^2.9.3" cosmiconfig "^9.0.0" css-functions-list "^3.2.3" css-tree "^3.1.0" - debug "^4.4.1" + debug "^4.4.3" fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" file-entry-cache "^10.1.4" From 9c69b78ba68a196e29a5e9f753f07e193308d6ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 05:12:39 +0000 Subject: [PATCH 13/77] chore(deps): update dependency stylelint-config-standard to v39.0.1 (#1294) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f388fb302c..f6e13c4f06 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "styled-components": "6.1.19", "stylelint": "16.25.0", "stylelint-config-prettier": "9.0.5", - "stylelint-config-standard": "39.0.0", + "stylelint-config-standard": "39.0.1", "testcafe": "3.7.2", "testcafe-browser-provider-electron": "0.0.21", "testcafe-react-selectors": "5.0.3", diff --git a/yarn.lock b/yarn.lock index a8c878ecea..e851456762 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19105,10 +19105,10 @@ stylelint-config-recommended@^17.0.0: resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-17.0.0.tgz#4f77c70609b2d7093cc60bb48adfabdde434aa5d" integrity sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA== -stylelint-config-standard@39.0.0: - version "39.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-39.0.0.tgz#9635554a9c42e7e89dadc024afac372d18e3e776" - integrity sha512-JabShWORb8Bmc1A47ZyJstran60P3yUdI1zWMpGYPeFiC6xzHXJMkpKAd8EjIhq3HPUplIWWMDJ/xu0AiPd+kA== +stylelint-config-standard@39.0.1: + version "39.0.1" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-39.0.1.tgz#dcd1c28400added09e566e85ffe8d480ae2531a2" + integrity sha512-b7Fja59EYHRNOTa3aXiuWnhUWXFU2Nfg6h61bLfAb5GS5fX3LMUD0U5t4S8N/4tpHQg3Acs2UVPR9jy2l1g/3A== dependencies: stylelint-config-recommended "^17.0.0" From 988e252e89f67afb15bfab23a516d54819f4f9d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:57:23 +0000 Subject: [PATCH 14/77] chore(deps): update dependency @types/react to v18.3.26 (#1295) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f6e13c4f06..6adc9e812e 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", "@types/node": "18.17.19", - "@types/react": "18.3.25", + "@types/react": "18.3.26", "@types/react-copy-to-clipboard": "5.0.7", "@types/react-dom": "18.3.7", "@types/react-redux": "7.1.34", diff --git a/yarn.lock b/yarn.lock index e851456762..b7ea855ad0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3352,10 +3352,10 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.3.25": - version "18.3.25" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.25.tgz#b37e3b05b6762b49f3944760f3bce3d5b6afa19b" - integrity sha512-oSVZmGtDPmRZtVDqvdKUi/qgCsWp5IDY29wp8na8Bj4B3cc99hfNzvNhlMkVVxctkAOGUA3Km7MMpBHAnWfcIA== +"@types/react@18.3.26": + version "18.3.26" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.26.tgz#4c5970878d30db3d2a0bca1e4eb5f258e391bbeb" + integrity sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA== dependencies: "@types/prop-types" "*" csstype "^3.0.2" From 1734e936100a061f39678ed98d997057b2ea864e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:39:15 +0000 Subject: [PATCH 15/77] chore(deps): update dependency less to v4.4.2 (#1296) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6adc9e812e..623c16cb42 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "jest-canvas-mock": "2.5.2", "jest-environment-jsdom-sixteen": "2.0.0", "js-yaml": "4.1.0", - "less": "4.4.0", + "less": "4.4.2", "less-loader": "12.3.0", "lint-staged": "16.2.3", "lndconnect": "0.2.10", diff --git a/yarn.lock b/yarn.lock index b7ea855ad0..fdbf942d6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13145,10 +13145,10 @@ less-loader@12.3.0: resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-12.3.0.tgz#d4a00361568be86a97da3df4f16954b0d4c15340" integrity sha512-0M6+uYulvYIWs52y0LqN4+QM9TqWAohYSNTo4htE8Z7Cn3G/qQMEmktfHmyJT23k+20kU9zHH2wrfFXkxNLtVw== -less@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/less/-/less-4.4.0.tgz#deaf881f4880ee80691beae925b8fac699d3a76d" - integrity sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w== +less@4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/less/-/less-4.4.2.tgz#fa4291fdb0334de91163622cc038f4bd3eb6b8d7" + integrity sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g== dependencies: copy-anything "^2.0.1" parse-node-version "^1.0.1" From 4a57dca6a0992084983b851cd6aa9774f6419e7c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 17:46:56 +0000 Subject: [PATCH 16/77] fix(deps): update dependency semver to v7.7.3 (#1297) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 623c16cb42..35519a7e19 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "electron-window-state": "5.0.3", "fs-extra": "11.1.0", "lodash": "4.17.21", - "semver": "7.7.2", + "semver": "7.7.3", "shell-env": "3.0.1", "unzipper": "0.12.3", "xterm": "5.3.0", diff --git a/yarn.lock b/yarn.lock index fdbf942d6e..88b82c5210 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17918,10 +17918,10 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@7.7.2: - version "7.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== +semver@7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" From d4acdace6595131d94984b9d6b80541946049869 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 18:03:40 +0000 Subject: [PATCH 17/77] chore(deps): update dependency lint-staged to v16.2.4 (#1298) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 35519a7e19..c6da8cb548 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.2", "less-loader": "12.3.0", - "lint-staged": "16.2.3", + "lint-staged": "16.2.4", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.1", diff --git a/yarn.lock b/yarn.lock index 88b82c5210..481c8820e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13195,15 +13195,15 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.3: - version "16.2.3" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.3.tgz#790866221d75602510507b5be40b2c7963715960" - integrity sha512-1OnJEESB9zZqsp61XHH2fvpS1es3hRCxMplF/AJUDa8Ho8VrscYDIuxGrj3m8KPXbcWZ8fT9XTMUhEQmOVKpKw== +lint-staged@16.2.4: + version "16.2.4" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.4.tgz#1f166370e32d9b7eb10583e86d86e1117f7ab489" + integrity sha512-Pkyr/wd90oAyXk98i/2KwfkIhoYQUMtss769FIT9hFM5ogYZwrk+GRE46yKXSg2ZGhcJ1p38Gf5gmI5Ohjg2yg== dependencies: commander "^14.0.1" listr2 "^9.0.4" micromatch "^4.0.8" - nano-spawn "^1.0.3" + nano-spawn "^2.0.0" pidtree "^0.6.0" string-argv "^0.3.2" yaml "^2.8.1" @@ -14097,10 +14097,10 @@ nan@^2.12.1, nan@^2.14.0, nan@^2.17.0, nan@^2.18.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== -nano-spawn@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.3.tgz#ef8d89a275eebc8657e67b95fc312a6527a05b8d" - integrity sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA== +nano-spawn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-2.0.0.tgz#f1250434c09ae18870d4f729fc54b406cf85a3e1" + integrity sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw== nanoid@^3.1.12, nanoid@^3.1.31, nanoid@^3.3.7: version "3.3.7" From eb5d0b07e2beb0f737dc1a70fd4e0c360fdd22f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:45:58 +0000 Subject: [PATCH 18/77] chore(deps): update actions/setup-node action to v6 (#1299) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06cdc9636d..dad92e9f2d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v5 - name: setup nodejs - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node_version }} cache: yarn From faddf65bf2689340fe896ed64b285abab98b1a1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 12:14:33 +0000 Subject: [PATCH 19/77] chore(deps): update dependency lint-staged to v16.2.5 (#1301) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c6da8cb548..6bfd1871a0 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.2", "less-loader": "12.3.0", - "lint-staged": "16.2.4", + "lint-staged": "16.2.5", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.1", diff --git a/yarn.lock b/yarn.lock index 481c8820e9..d1e688ba0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13195,10 +13195,10 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.4: - version "16.2.4" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.4.tgz#1f166370e32d9b7eb10583e86d86e1117f7ab489" - integrity sha512-Pkyr/wd90oAyXk98i/2KwfkIhoYQUMtss769FIT9hFM5ogYZwrk+GRE46yKXSg2ZGhcJ1p38Gf5gmI5Ohjg2yg== +lint-staged@16.2.5: + version "16.2.5" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.5.tgz#85f9dbe48f379217b7b0554be17c9da222f373a6" + integrity sha512-o36wH3OX0jRWqDw5dOa8a8x6GXTKaLM+LvhRaucZxez0IxA+KNDUCiyjBfNgsMNmchwSX6urLSL7wShcUqAang== dependencies: commander "^14.0.1" listr2 "^9.0.4" From ca15e9730bffb9c0a6eaa0327c9d13c1ae2c0541 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 04:47:39 +0000 Subject: [PATCH 20/77] chore(deps): update dependency lint-staged to v16.2.6 (#1304) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 6bfd1871a0..2b773607c1 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.0", "less": "4.4.2", "less-loader": "12.3.0", - "lint-staged": "16.2.5", + "lint-staged": "16.2.6", "lndconnect": "0.2.10", "nodemon": "3.1.10", "patch-package": "8.0.1", diff --git a/yarn.lock b/yarn.lock index d1e688ba0e..21bf095ac1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13195,13 +13195,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.5: - version "16.2.5" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.5.tgz#85f9dbe48f379217b7b0554be17c9da222f373a6" - integrity sha512-o36wH3OX0jRWqDw5dOa8a8x6GXTKaLM+LvhRaucZxez0IxA+KNDUCiyjBfNgsMNmchwSX6urLSL7wShcUqAang== +lint-staged@16.2.6: + version "16.2.6" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.6.tgz#760675e80f4b53337083d3f8bdecdd1f88079bf5" + integrity sha512-s1gphtDbV4bmW1eylXpVMk2u7is7YsrLl8hzrtvC70h4ByhcMLZFY01Fx05ZUDNuv1H8HO4E+e2zgejV1jVwNw== dependencies: commander "^14.0.1" - listr2 "^9.0.4" + listr2 "^9.0.5" micromatch "^4.0.8" nano-spawn "^2.0.0" pidtree "^0.6.0" @@ -13215,10 +13215,10 @@ linux-platform-info@^0.0.3: dependencies: os-family "^1.0.0" -listr2@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.4.tgz#2916e633ae6e09d1a3f981172937ac1c5a8fa64f" - integrity sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ== +listr2@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.5.tgz#92df7c4416a6da630eb9ef46da469b70de97b316" + integrity sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g== dependencies: cli-truncate "^5.0.0" colorette "^2.0.20" From c74d807ff3fd6aedfcd2dff0b413bf17faae4c45 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 09:07:34 +0000 Subject: [PATCH 21/77] chore(deps): update dependency @types/archiver to v6.0.4 (#1305) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2b773607c1..6742eca27c 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", "@testing-library/user-event": "14.6.1", - "@types/archiver": "6.0.3", + "@types/archiver": "6.0.4", "@types/detect-port": "1.3.5", "@types/dockerode": "3.3.44", "@types/fs-extra": "9.0.13", diff --git a/yarn.lock b/yarn.lock index 21bf095ac1..d145ba3766 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3006,10 +3006,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/archiver@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-6.0.3.tgz#074eb6f4febc0128c25a205a8263da3d4688df53" - integrity sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ== +"@types/archiver@6.0.4": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-6.0.4.tgz#c2497d7f009b97fdd9eed6fd1a15bc82abd9dc13" + integrity sha512-ULdQpARQ3sz9WH4nb98mJDYA0ft2A8C4f4fovvUcFwINa1cgGjY36JCAYuP5YypRq4mco1lJp1/7jEMS2oR0Hg== dependencies: "@types/readdir-glob" "*" From d9b71bcf4560ad4487bb28cd0477a24bb9049129 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 12:46:32 +0000 Subject: [PATCH 22/77] chore(deps): update dependency @types/dockerode to v3.3.45 (#1306) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6742eca27c..1692f3498f 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@testing-library/user-event": "14.6.1", "@types/archiver": "6.0.4", "@types/detect-port": "1.3.5", - "@types/dockerode": "3.3.44", + "@types/dockerode": "3.3.45", "@types/fs-extra": "9.0.13", "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", diff --git a/yarn.lock b/yarn.lock index d145ba3766..991cc8f13e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3078,10 +3078,10 @@ "@types/node" "*" "@types/ssh2" "*" -"@types/dockerode@3.3.44": - version "3.3.44" - resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.44.tgz#1e6d5b291646820e9daabfa132cdb33c9d535b56" - integrity sha512-fUpIHlsbYpxAJb285xx3vp7q5wf5mjqSn3cYwl/MhiM+DB99OdO5sOCPlO0PjO+TyOtphPs7tMVLU/RtOo/JjA== +"@types/dockerode@3.3.45": + version "3.3.45" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.45.tgz#1b5f19301563acf811adc13a6b2b3e0981998a5e" + integrity sha512-iYpZF+xr5QLpIICejLdUF2r5gh8IXY1Gw3WLmt41dUbS3Vn/3hVgL+6lJBVbmrhYBWfbWPPstdr6+A0s95DTWA== dependencies: "@types/docker-modem" "*" "@types/node" "*" From 6bc29d0ca8f2f049b899f7536eb12cb3993fb129 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 05:03:51 +0000 Subject: [PATCH 23/77] chore(deps): update node.js to v22.21.0 (#1274) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/litd/src.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/litd/src.Dockerfile b/docker/litd/src.Dockerfile index f2cf26a261..6b57d8296b 100644 --- a/docker/litd/src.Dockerfile +++ b/docker/litd/src.Dockerfile @@ -1,5 +1,5 @@ # Start with a NodeJS base image that also contains yarn. -FROM node:22.14.0-alpine@sha256:9bef0ef1e268f60627da9ba7d7605e8831d5b56ad07487d24d1aa386336d1944 as nodejsbuilder +FROM node:22.21.0-alpine@sha256:bd26af08779f746650d95a2e4d653b0fd3c8030c44284b6b98d701c9b5eb66b9 as nodejsbuilder ARG LITD_VERSION From 36920a49a0b5f6939ecd8a4336016dcb7a261ee0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 18:03:41 +0000 Subject: [PATCH 24/77] chore(deps): update dependency @types/archiver to v7 (#1308) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1692f3498f..f4b273fe8c 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", "@testing-library/user-event": "14.6.1", - "@types/archiver": "6.0.4", + "@types/archiver": "7.0.0", "@types/detect-port": "1.3.5", "@types/dockerode": "3.3.45", "@types/fs-extra": "9.0.13", diff --git a/yarn.lock b/yarn.lock index 991cc8f13e..12f2f1446c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3006,10 +3006,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/archiver@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-6.0.4.tgz#c2497d7f009b97fdd9eed6fd1a15bc82abd9dc13" - integrity sha512-ULdQpARQ3sz9WH4nb98mJDYA0ft2A8C4f4fovvUcFwINa1cgGjY36JCAYuP5YypRq4mco1lJp1/7jEMS2oR0Hg== +"@types/archiver@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-7.0.0.tgz#475d5aa4076ffc05f2c78dc7540b0ea4ab8c7d7a" + integrity sha512-/3vwGwx9n+mCQdYZ2IKGGHEFL30I96UgBlk8EtRDDFQ9uxM1l4O5Ci6r00EMAkiDaTqD9DQ6nVrWRICnBPtzzg== dependencies: "@types/readdir-glob" "*" From 7a65b37a80bcfb4e96b683429fd13abb21cd903b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 05:52:36 +0000 Subject: [PATCH 25/77] chore(deps): update node.js to v22.21.1 (#1310) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/litd/src.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/litd/src.Dockerfile b/docker/litd/src.Dockerfile index 6b57d8296b..4d373088b6 100644 --- a/docker/litd/src.Dockerfile +++ b/docker/litd/src.Dockerfile @@ -1,5 +1,5 @@ # Start with a NodeJS base image that also contains yarn. -FROM node:22.21.0-alpine@sha256:bd26af08779f746650d95a2e4d653b0fd3c8030c44284b6b98d701c9b5eb66b9 as nodejsbuilder +FROM node:22.21.1-alpine@sha256:b2358485e3e33bc3a33114d2b1bdb18cdbe4df01bd2b257198eb51beb1f026c5 as nodejsbuilder ARG LITD_VERSION From 8aa405ccb804c723c480c4666448595434565d3b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 05:51:44 +0000 Subject: [PATCH 26/77] chore(deps): update dependency wait-on to v9.0.3 (#1311) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index f4b273fe8c..e1175d5ffa 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "ts-node": "10.9.2", "typescript": "5.5.4", "utf-8-validate": "6.0.5", - "wait-on": "9.0.1", + "wait-on": "9.0.3", "webpack": "4.44.2", "ws": "8.18.3" }, diff --git a/yarn.lock b/yarn.lock index 12f2f1446c..80ba0f6282 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4772,10 +4772,10 @@ axe-core@=4.7.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axios@^1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.12.2.tgz#6c307390136cf7a2278d09cec63b136dfc6e6da7" - integrity sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw== +axios@^1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.2.tgz#9ada120b7b5ab24509553ec3e40123521117f687" + integrity sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA== dependencies: follow-redirects "^1.15.6" form-data "^4.0.4" @@ -20707,12 +20707,12 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" -wait-on@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-9.0.1.tgz#c5f2c3094b8e808a241cf41d2aaecd4f762907ec" - integrity sha512-noeCAI+XbqWMXY23sKril0BSURhuLYarkVXwJv1uUWwoojZJE7pmX3vJ7kh7SZaNgPGzfsCSQIZM/AGvu0Q9pA== +wait-on@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-9.0.3.tgz#3ea858db0b854039e6aff5f323885aaef25e32bf" + integrity sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA== dependencies: - axios "^1.12.2" + axios "^1.13.2" joi "^18.0.1" lodash "^4.17.21" minimist "^1.2.8" From 54662e9559e9e4a3c073d8edcd9de3dae3f2f4d8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:47:41 +0000 Subject: [PATCH 27/77] chore(deps): update eclipse-temurin docker tag (#1312) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/eclair/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/eclair/Dockerfile b/docker/eclair/Dockerfile index 7307abcd53..3316e1a0ba 100644 --- a/docker/eclair/Dockerfile +++ b/docker/eclair/Dockerfile @@ -1,7 +1,7 @@ ######################### # Original Source: https://github.com/ACINQ/eclair/blob/v0.12.0/Dockerfile ######################### -FROM eclipse-temurin:25-jdk-alpine as BUILD +FROM eclipse-temurin:25.0.1_8-jdk-alpine as BUILD # Let's fetch eclair dependencies, so that Docker can cache them # This way we won't have to fetch dependencies again if only the source code changes @@ -55,7 +55,7 @@ RUN cp -R -f /usr/repo/* . RUN ./mvnw package -pl eclair-node -am -DskipTests -Dgit.commit.id=notag -Dgit.commit.id.abbrev=notag -o # It might be good idea to run the tests here, so that the docker build fail if the code is bugged -FROM eclipse-temurin:25-jre-alpine +FROM eclipse-temurin:25.0.1_8-jre-alpine WORKDIR /app # install jq for eclair-cli From a56bf6183a77c2a22513ce16a6dfbd220c0d015b Mon Sep 17 00:00:00 2001 From: Jemimah Nagasha Date: Sun, 19 Oct 2025 16:54:45 +0300 Subject: [PATCH 28/77] feat(networks): retain custom block count input --- .../bitcoin/actions/MineBlocksInput.tsx | 15 ++++++++---- src/store/models/network.ts | 23 +++++++++++++++++++ src/types/index.ts | 1 + src/utils/network.ts | 3 +++ src/utils/tests/helpers.ts | 1 + 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/components/designer/bitcoin/actions/MineBlocksInput.tsx b/src/components/designer/bitcoin/actions/MineBlocksInput.tsx index c8bb21e7f8..2bf25fc63a 100644 --- a/src/components/designer/bitcoin/actions/MineBlocksInput.tsx +++ b/src/components/designer/bitcoin/actions/MineBlocksInput.tsx @@ -5,7 +5,7 @@ import styled from '@emotion/styled'; import { Button, Form, Input, InputNumber } from 'antd'; import { usePrefixedTranslation } from 'hooks'; import { BitcoinNode } from 'shared/types'; -import { useStoreActions } from 'store'; +import { useStoreActions, useStoreState } from 'store'; const InputGroup = Input.Group; @@ -20,12 +20,17 @@ const Styled = { const MineBlocksInput: React.FC<{ node: BitcoinNode }> = ({ node }) => { const { l } = usePrefixedTranslation('cmps.designer.bitcoind.MineBlocksInput'); - const [value, setValue] = useState(6); + const network = useStoreState(s => s.network.networkById(node.networkId)); const { notify } = useStoreActions(s => s.app); const { mine } = useStoreActions(s => s.bitcoin); + const { updateManualMineCount } = useStoreActions(actions => actions.network); + + const [count, setCount] = useState(network.manualMineCount); + const mineAsync = useAsyncCallback(async () => { try { - await mine({ blocks: value, node }); + await mine({ blocks: count, node }); + await updateManualMineCount({ id: node.networkId, count }); } catch (error: any) { notify({ message: l('error'), error }); } @@ -35,9 +40,9 @@ const MineBlocksInput: React.FC<{ node: BitcoinNode }> = ({ node }) => { setValue(parseInt(v as any))} + onChange={v => setCount(parseInt(v as any))} disabled={mineAsync.loading} /> ; + manualMineCount: number; } export interface AutoMinerModel { @@ -192,6 +193,14 @@ export interface NetworkModel { setAutoMineMode: Action; setMiningState: Action; mineBlock: Thunk; + setManualMineCount: Action; + updateManualMineCount: Thunk< + NetworkModel, + { id: number; count: number }, + StoreInjections, + RootModel, + Promise + >; } const networkModel: NetworkModel = { @@ -286,6 +295,7 @@ const networkModel: NetworkModel = { managedImages: computedManagedImages, customImages, basePorts: settings.basePorts, + manualMineCount: 6, }); actions.add(network); const { networks } = getState(); @@ -1074,6 +1084,19 @@ const networkModel: NetworkModel = { } }, ), + setManualMineCount: action((state, { id, count }) => { + const network = state.networks.find(n => n.id === id); + if (!network) throw new Error(l('networkByIdErr', { networkId: id })); + network.manualMineCount = count; + }), + updateManualMineCount: thunk(async (actions, { id, count }, { getState }) => { + const networks = getState().networks; + const network = networks.find(n => n.id === id); + if (!network) throw new Error(l('networkByIdErr', { networkId: id })); + + actions.setManualMineCount({ id, count }); + await actions.save(); + }), }; export default networkModel; diff --git a/src/types/index.ts b/src/types/index.ts index a70c89830b..ee01a5d322 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -31,6 +31,7 @@ export interface Network { lightning: LightningNode[]; tap: TapNode[]; }; + manualMineCount: number; } /** diff --git a/src/utils/network.ts b/src/utils/network.ts index d8106052f1..5f826c7b5f 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -456,6 +456,7 @@ export const createNetwork = (config: { customImages: { image: CustomImage; count: number }[]; status?: Status; basePorts?: NodeBasePorts; + manualMineCount: number; }): Network => { const { id, @@ -471,6 +472,7 @@ export const createNetwork = (config: { managedImages, customImages, basePorts, + manualMineCount, } = config; // need explicit undefined check because Status.Starting is 0 const status = config.status !== undefined ? config.status : Status.Stopped; @@ -487,6 +489,7 @@ export const createNetwork = (config: { tap: [], }, autoMineMode: AutoMineMode.AutoOff, + manualMineCount, }; const { bitcoin, lightning } = network.nodes; diff --git a/src/utils/tests/helpers.ts b/src/utils/tests/helpers.ts index 456214d71c..537e1cbc1f 100644 --- a/src/utils/tests/helpers.ts +++ b/src/utils/tests/helpers.ts @@ -240,6 +240,7 @@ export const getNetwork = ( repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }; if (tapNodeCount > 0) { config.lndNodes = 0; From 8a7472282aa8f34989d7ae093007ec61e77feb91 Mon Sep 17 00:00:00 2001 From: Jemimah Nagasha Date: Sun, 19 Oct 2025 20:45:07 +0300 Subject: [PATCH 29/77] test(network): adding missing tests --- src/store/models/network.spec.ts | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/store/models/network.spec.ts b/src/store/models/network.spec.ts index 745d9a2276..3b70fa47c8 100644 --- a/src/store/models/network.spec.ts +++ b/src/store/models/network.spec.ts @@ -65,6 +65,7 @@ describe('Network model', () => { tapdNodes: 0, litdNodes: 1, customNodes: {}, + manualMineCount: 6, }; beforeEach(() => { @@ -1023,6 +1024,42 @@ describe('Network model', () => { }); }); + describe('ManualMineCount', () => { + beforeEach(async () => { + await store.getActions().network.addNetwork(addNetworkArgs); + }); + + it('should set manual mine count for a network', () => { + const { setManualMineCount } = store.getActions().network; + const networkId = firstNetwork().id; + + expect(firstNetwork().manualMineCount).toBe(6); + setManualMineCount({ id: networkId, count: 10 }); + expect(firstNetwork().manualMineCount).toBe(10); + }); + + it('should fail to set manual mine count with invalid network id', () => { + const { setManualMineCount } = store.getActions().network; + expect(() => setManualMineCount({ id: 999, count: 10 })).toThrow( + "Network with the id '999' was not found.", + ); + }); + + it('should update manual mine count and persist changes', async () => { + const { updateManualMineCount } = store.getActions().network; + const networkId = firstNetwork().id; + await updateManualMineCount({ id: networkId, count: 15 }); + expect(firstNetwork().manualMineCount).toBe(15); + }); + + it('should fail to update manual mine count with invalid network id', () => { + const { updateManualMineCount } = store.getActions().network; + expect(() => updateManualMineCount({ id: 999, count: 10 })).rejects.toThrow( + "Network with the id '999' was not found.", + ); + }); + }); + describe('Other actions', () => { it('should remove a network', async () => { expect(store.getState().network.networks).toHaveLength(0); From 51e2d3c34e3d8a27200c35fb8826837d0a45b5df Mon Sep 17 00:00:00 2001 From: Jemimah Nagasha Date: Mon, 20 Oct 2025 18:04:30 +0300 Subject: [PATCH 30/77] fix: missing type property --- src/components/common/RenameNodeModal.spec.tsx | 3 ++- .../designer/bitcoin/actions/SendOnChainModal.spec.tsx | 3 ++- .../lightning/actions/CreateInvoiceModal.spec.tsx | 1 + .../designer/lightning/actions/OpenChannelModal.spec.tsx | 1 + .../designer/lightning/actions/PayInvoiceModal.spec.tsx | 1 + src/components/network/ImportNetwork.spec.tsx | 1 + src/lib/docker/composeFile.spec.ts | 1 + src/lib/docker/dockerService.spec.ts | 9 +++++++++ src/lib/litd/litdProxyClient.spec.ts | 1 + src/lib/litd/litdService.spec.ts | 1 + src/store/models/designer.spec.ts | 4 ++++ src/store/models/lit.spec.ts | 1 + src/utils/network.spec.ts | 2 ++ 13 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/common/RenameNodeModal.spec.tsx b/src/components/common/RenameNodeModal.spec.tsx index c77a128005..5a8f14739b 100644 --- a/src/components/common/RenameNodeModal.spec.tsx +++ b/src/components/common/RenameNodeModal.spec.tsx @@ -6,9 +6,9 @@ import { initChartFromNetwork } from 'utils/chart'; import { defaultRepoState } from 'utils/constants'; import { createNetwork } from 'utils/network'; import { + bitcoinServiceMock, injections, lightningServiceMock, - bitcoinServiceMock, litdServiceMock, renderWithProviders, tapServiceMock, @@ -41,6 +41,7 @@ describe('RenameNodeModal', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const initialState = { network: { diff --git a/src/components/designer/bitcoin/actions/SendOnChainModal.spec.tsx b/src/components/designer/bitcoin/actions/SendOnChainModal.spec.tsx index 73d3d63451..78531a0c70 100644 --- a/src/components/designer/bitcoin/actions/SendOnChainModal.spec.tsx +++ b/src/components/designer/bitcoin/actions/SendOnChainModal.spec.tsx @@ -6,10 +6,10 @@ import { initChartFromNetwork } from 'utils/chart'; import { defaultRepoState } from 'utils/constants'; import { createNetwork } from 'utils/network'; import { + bitcoinServiceMock, renderWithProviders, suppressConsoleErrors, testManagedImages, - bitcoinServiceMock, } from 'utils/tests'; import SendOnChainModal from './SendOnChainModal'; @@ -31,6 +31,7 @@ describe('SendOnChainModal', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const initialState = { diff --git a/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx b/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx index c092bedda4..7a1939ee6b 100644 --- a/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx +++ b/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx @@ -150,6 +150,7 @@ describe('CreateInvoiceModal', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const asset: LightningNodeChannelAsset = { id: 'abcd', diff --git a/src/components/designer/lightning/actions/OpenChannelModal.spec.tsx b/src/components/designer/lightning/actions/OpenChannelModal.spec.tsx index 8e1a4ac755..d76da8723d 100644 --- a/src/components/designer/lightning/actions/OpenChannelModal.spec.tsx +++ b/src/components/designer/lightning/actions/OpenChannelModal.spec.tsx @@ -288,6 +288,7 @@ describe('OpenChannelModal', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const asset: LightningNodeChannelAsset = { id: 'abcd', diff --git a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx index b9bf825f55..7d3c97c79f 100644 --- a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx +++ b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx @@ -149,6 +149,7 @@ describe('PayInvoiceModal', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const asset: LightningNodeChannelAsset = { id: 'abcd', diff --git a/src/components/network/ImportNetwork.spec.tsx b/src/components/network/ImportNetwork.spec.tsx index ded5bbb11d..9a7bf054fa 100644 --- a/src/components/network/ImportNetwork.spec.tsx +++ b/src/components/network/ImportNetwork.spec.tsx @@ -72,6 +72,7 @@ describe('ImportNetwork component', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); chart = initChartFromNetwork(network); filesMock.read.mockResolvedValue(JSON.stringify({ network, chart })); diff --git a/src/lib/docker/composeFile.spec.ts b/src/lib/docker/composeFile.spec.ts index d9bfb59f46..c9605ae0e9 100644 --- a/src/lib/docker/composeFile.spec.ts +++ b/src/lib/docker/composeFile.spec.ts @@ -19,6 +19,7 @@ describe('ComposeFile', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const btcNode = network.nodes.bitcoin[0]; const lndNode = network.nodes.lightning[0] as LndNode; diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index ace1c4520d..44b7e49ff7 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -192,6 +192,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); net.nodes.lightning[0].backendName = 'invalid'; dockerService.saveComposeFile(net); @@ -217,6 +218,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); net.nodes.lightning[0].backendName = 'invalid'; dockerService.saveComposeFile(net); @@ -242,6 +244,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); net.nodes.lightning[0].backendName = 'invalid'; dockerService.saveComposeFile(net); @@ -308,6 +311,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); dockerService.saveComposeFile(net); const { backendName } = net.nodes.lightning[0] as LitdNode; @@ -331,6 +335,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const litdNode = net.nodes.lightning[0] as LitdNode; litdNode.backendName = 'invalid'; @@ -357,6 +362,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); net.nodes.lightning[0].implementation = 'unknown' as any; dockerService.saveComposeFile(net); @@ -392,6 +398,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const chart = initChartFromNetwork(net); // return 'any' to suppress "The operand of a 'delete' operator must be optional.ts(2790)" error @@ -522,6 +529,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const chart = initChartFromNetwork(net); const fileData: NetworksFile = { @@ -716,6 +724,7 @@ describe('DockerService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); composeMock.upAll.mockResolvedValue(mockResult); await dockerService.start(net); diff --git a/src/lib/litd/litdProxyClient.spec.ts b/src/lib/litd/litdProxyClient.spec.ts index 608b2188c4..ef8d619572 100644 --- a/src/lib/litd/litdProxyClient.spec.ts +++ b/src/lib/litd/litdProxyClient.spec.ts @@ -20,6 +20,7 @@ describe('LitdProxyClient', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const node = network.nodes.lightning[0] as LitdNode; let actualIpc: IpcSender; diff --git a/src/lib/litd/litdService.spec.ts b/src/lib/litd/litdService.spec.ts index 3760134547..883a886bb7 100644 --- a/src/lib/litd/litdService.spec.ts +++ b/src/lib/litd/litdService.spec.ts @@ -24,6 +24,7 @@ describe('LitdService', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const node = network.nodes.lightning[0] as LitdNode; diff --git a/src/store/models/designer.spec.ts b/src/store/models/designer.spec.ts index 7d42244824..7139b18805 100644 --- a/src/store/models/designer.spec.ts +++ b/src/store/models/designer.spec.ts @@ -133,6 +133,7 @@ describe('Designer model', () => { tapdNodes: 0, litdNodes: 0, customNodes: {}, + manualMineCount: 6, }); store.getActions().designer.setActiveId(firstNetwork().id); const { removeChart } = store.getActions().designer; @@ -581,6 +582,7 @@ describe('Designer model', () => { tapdNodes: 0, litdNodes: 0, customNodes: {}, + manualMineCount: 6, }); const newId = store.getState().network.networks[1].id; setActiveId(newId); @@ -610,6 +612,7 @@ describe('Designer model', () => { tapdNodes: 0, litdNodes: 0, customNodes: {}, + manualMineCount: 6, }); const newId = store.getState().network.networks[1].id; setActiveId(newId); @@ -647,6 +650,7 @@ describe('Designer model', () => { tapdNodes: 0, litdNodes: 0, customNodes: {}, + manualMineCount: 0, }); const newId = store.getState().network.networks[1].id; setActiveId(newId); diff --git a/src/store/models/lit.spec.ts b/src/store/models/lit.spec.ts index d808ba928c..10f7822de3 100644 --- a/src/store/models/lit.spec.ts +++ b/src/store/models/lit.spec.ts @@ -44,6 +44,7 @@ describe('LIT Model', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); const initialState = { network: { diff --git a/src/utils/network.spec.ts b/src/utils/network.spec.ts index 05efdf07dd..c7024963a1 100644 --- a/src/utils/network.spec.ts +++ b/src/utils/network.spec.ts @@ -163,6 +163,7 @@ describe('Network Utils', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); }); @@ -507,6 +508,7 @@ describe('Network Utils', () => { repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], + manualMineCount: 6, }); }); From 21a066514a4102cd4948fe1bf12199e857e2c8af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 05:03:56 +0000 Subject: [PATCH 31/77] chore(deps): update dependency nodemon to v3.1.11 (#1313) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e1175d5ffa..3f4dc2f7a7 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "less-loader": "12.3.0", "lint-staged": "16.2.6", "lndconnect": "0.2.10", - "nodemon": "3.1.10", + "nodemon": "3.1.11", "patch-package": "8.0.1", "prettier": "2.8.8", "react": "17.0.2", diff --git a/yarn.lock b/yarn.lock index 80ba0f6282..318a687ed2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14267,10 +14267,10 @@ node-releases@^2.0.18: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -nodemon@3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.10.tgz#5015c5eb4fffcb24d98cf9454df14f4fecec9bc1" - integrity sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw== +nodemon@3.1.11: + version "3.1.11" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.11.tgz#04a54d1e794fbec9d8f6ffd8bf1ba9ea93a756ed" + integrity sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g== dependencies: chokidar "^3.5.2" debug "^4" From 49540a59560f70d87a9141f3842d4b6d29257ec0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:38:44 +0000 Subject: [PATCH 32/77] chore(deps): update dependency js-yaml to v4.1.1 (#1314) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3f4dc2f7a7..86b435349d 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "i18next-scanner": "4.6.0", "jest-canvas-mock": "2.5.2", "jest-environment-jsdom-sixteen": "2.0.0", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "less": "4.4.2", "less-loader": "12.3.0", "lint-staged": "16.2.6", diff --git a/yarn.lock b/yarn.lock index 318a687ed2..ca001ffe5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12807,10 +12807,10 @@ js-tokens@^3.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== +js-yaml@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -12822,6 +12822,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" From d2428d2c3331882e6d9363d5c5e213848e2967c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 16 Nov 2025 04:27:15 +0000 Subject: [PATCH 33/77] chore(deps): update dependency @types/dockerode to v3.3.46 (#1316) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 86b435349d..0b3c43152e 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@testing-library/user-event": "14.6.1", "@types/archiver": "7.0.0", "@types/detect-port": "1.3.5", - "@types/dockerode": "3.3.45", + "@types/dockerode": "3.3.46", "@types/fs-extra": "9.0.13", "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", diff --git a/yarn.lock b/yarn.lock index ca001ffe5d..7e01e30000 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3078,10 +3078,10 @@ "@types/node" "*" "@types/ssh2" "*" -"@types/dockerode@3.3.45": - version "3.3.45" - resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.45.tgz#1b5f19301563acf811adc13a6b2b3e0981998a5e" - integrity sha512-iYpZF+xr5QLpIICejLdUF2r5gh8IXY1Gw3WLmt41dUbS3Vn/3hVgL+6lJBVbmrhYBWfbWPPstdr6+A0s95DTWA== +"@types/dockerode@3.3.46": + version "3.3.46" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.46.tgz#7ad0e63f9244aab45fb8145abad161d1cd75acb8" + integrity sha512-pvvaYMN3PKXMvWi7A1UNMgqXpWD4+AWfmTFK1kCxfSXW7dMigaeyufRM9tAJf+sy4CX6tKn76z/fR6ut2SZsrg== dependencies: "@types/docker-modem" "*" "@types/node" "*" From 57c742fa4f69c58de8a72958d8be23cf88778a9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 08:59:53 +0000 Subject: [PATCH 34/77] chore(deps): update dependency @types/react to v18.3.27 (#1317) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0b3c43152e..57b72b61e7 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", "@types/node": "18.17.19", - "@types/react": "18.3.26", + "@types/react": "18.3.27", "@types/react-copy-to-clipboard": "5.0.7", "@types/react-dom": "18.3.7", "@types/react-redux": "7.1.34", diff --git a/yarn.lock b/yarn.lock index 7e01e30000..fdf09cffac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3352,13 +3352,13 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.3.26": - version "18.3.26" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.26.tgz#4c5970878d30db3d2a0bca1e4eb5f258e391bbeb" - integrity sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA== +"@types/react@18.3.27": + version "18.3.27" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.27.tgz#74a3b590ea183983dc65a474dc17553ae1415c34" + integrity sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w== dependencies: "@types/prop-types" "*" - csstype "^3.0.2" + csstype "^3.2.2" "@types/react@^17": version "17.0.74" @@ -7102,6 +7102,11 @@ csstype@3.1.3, csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + cyclist@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.2.tgz#673b5f233bf34d8e602b949429f8171d9121bea3" From a57a0665ac2a0282ed4e86314adb9e9c4b6de5ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 22:11:19 +0000 Subject: [PATCH 35/77] chore(deps): update dependency @types/dockerode to v3.3.47 (#1318) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 57b72b61e7..f2dfe12100 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@testing-library/user-event": "14.6.1", "@types/archiver": "7.0.0", "@types/detect-port": "1.3.5", - "@types/dockerode": "3.3.46", + "@types/dockerode": "3.3.47", "@types/fs-extra": "9.0.13", "@types/jest": "30.0.0", "@types/js-yaml": "4.0.9", diff --git a/yarn.lock b/yarn.lock index fdf09cffac..b215ac49eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3078,10 +3078,10 @@ "@types/node" "*" "@types/ssh2" "*" -"@types/dockerode@3.3.46": - version "3.3.46" - resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.46.tgz#7ad0e63f9244aab45fb8145abad161d1cd75acb8" - integrity sha512-pvvaYMN3PKXMvWi7A1UNMgqXpWD4+AWfmTFK1kCxfSXW7dMigaeyufRM9tAJf+sy4CX6tKn76z/fR6ut2SZsrg== +"@types/dockerode@3.3.47": + version "3.3.47" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.47.tgz#cf8c6b4efcd0bb28b0e6009e613e7faab1b96e75" + integrity sha512-ShM1mz7rCjdssXt7Xz0u1/R2BJC7piWa3SJpUBiVjCf2A3XNn4cP6pUVaD8bLanpPVVn4IKzJuw3dOvkJ8IbYw== dependencies: "@types/docker-modem" "*" "@types/node" "*" From ee1173559f1e551fbdb94f4dbf5414b8350c68cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 04:41:09 +0000 Subject: [PATCH 36/77] chore(deps): update dependency lint-staged to v16.2.7 (#1319) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index f2dfe12100..6ab8ce6550 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "js-yaml": "4.1.1", "less": "4.4.2", "less-loader": "12.3.0", - "lint-staged": "16.2.6", + "lint-staged": "16.2.7", "lndconnect": "0.2.10", "nodemon": "3.1.11", "patch-package": "8.0.1", diff --git a/yarn.lock b/yarn.lock index b215ac49eb..eaf414dd1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6136,10 +6136,10 @@ commander@2.11.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== -commander@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.1.tgz#2f9225c19e6ebd0dc4404dd45821b2caa17ea09b" - integrity sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A== +commander@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" + integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== commander@^2.20.0: version "2.20.3" @@ -13207,12 +13207,12 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@16.2.6: - version "16.2.6" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.6.tgz#760675e80f4b53337083d3f8bdecdd1f88079bf5" - integrity sha512-s1gphtDbV4bmW1eylXpVMk2u7is7YsrLl8hzrtvC70h4ByhcMLZFY01Fx05ZUDNuv1H8HO4E+e2zgejV1jVwNw== +lint-staged@16.2.7: + version "16.2.7" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.2.7.tgz#c4a635960c17b52fe774f1f40aee8ce1bd86531f" + integrity sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow== dependencies: - commander "^14.0.1" + commander "^14.0.2" listr2 "^9.0.5" micromatch "^4.0.8" nano-spawn "^2.0.0" From 3ddaa4ae61c907682310902dcaee5c8e503f7a36 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:44:02 +0000 Subject: [PATCH 37/77] chore(deps): update actions/checkout action to v6 (#1320) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dad92e9f2d..670116b8b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: if: matrix.os == 'ubuntu-latest' run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: setup nodejs uses: actions/setup-node@v6 From b991169a16586bba526a2f348db38f1c449cdb1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:00:31 +0000 Subject: [PATCH 38/77] chore(deps): update dependency stylelint to v16.26.0 (#1321) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 113 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 79 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 6ab8ce6550..a92eae8fbb 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "standard-version": "9.5.0", "strip-ansi": "6.0.1", "styled-components": "6.1.19", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-prettier": "9.0.5", "stylelint-config-standard": "39.0.1", "testcafe": "3.7.2", diff --git a/yarn.lock b/yarn.lock index eaf414dd1e..2cd0ee42d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1518,6 +1518,24 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@cacheable/memory@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@cacheable/memory/-/memory-2.0.5.tgz#318ab34664a4347fb4b21828761da9794cf518e2" + integrity sha512-fkiAxCvssEyJZ5fxX4tcdZFRmW9JehSTGvvqmXn6rTzG5cH6V/3C4ad8yb01vOjp2xBydHkHrgpW0qeGtzt6VQ== + dependencies: + "@cacheable/utils" "^2.3.0" + "@keyv/bigmap" "^1.1.0" + hookified "^1.12.2" + keyv "^5.5.4" + +"@cacheable/utils@^2.3.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@cacheable/utils/-/utils-2.3.1.tgz#28901ec521cb6336073147dfc2ef6c8081510ff5" + integrity sha512-38NJXjIr4W1Sghun8ju+uYWD8h2c61B4dKwfnQHVDFpAJ9oS28RpfqZQJ6Dgd3RceGkILDY9YT+72HJR3LoeSQ== + dependencies: + hashery "^1.2.0" + keyv "^5.5.4" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -2532,10 +2550,18 @@ resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== -"@keyv/serialize@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.1.0.tgz#08f5d89096110fdcf778e5337362e1cd5afad70a" - integrity sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g== +"@keyv/bigmap@^1.1.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@keyv/bigmap/-/bigmap-1.3.0.tgz#f06d9bb38488a59f012cd2758e6f429dfd312fb5" + integrity sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg== + dependencies: + hashery "^1.2.0" + hookified "^1.13.0" + +"@keyv/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.1.1.tgz#0c01dd3a3483882af7cf3878d4e71d505c81fc4a" + integrity sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA== "@lightningpolar/litd-api@0.15.0-alpha.rc1": version "0.15.0-alpha.rc1" @@ -5546,13 +5572,16 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable@^1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/cacheable/-/cacheable-1.10.4.tgz#874c7ac005e9127e1daa3b09dbb4fd01743a4e91" - integrity sha512-Gd7ccIUkZ9TE2odLQVS+PDjIvQCdJKUlLdJRVvZu0aipj07Qfx+XIej7hhDrKGGoIxV5m5fT/kOJNJPQhQneRg== +cacheable@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cacheable/-/cacheable-2.2.0.tgz#1b63ff365016a2bae9072e2d022393170abf603e" + integrity sha512-LEJxRqfeomiiRd2t0uON6hxAtgOoWDfY3fugebbz+J3vDLO+SkdfFChQcOHTZhj9SYa9iwE9MGYNX72dKiOE4w== dependencies: - hookified "^1.11.0" - keyv "^5.5.0" + "@cacheable/memory" "^2.0.5" + "@cacheable/utils" "^2.3.0" + hookified "^1.13.0" + keyv "^5.5.4" + qified "^0.5.2" cachedir@2.3.0: version "2.3.0" @@ -9403,12 +9432,12 @@ figures@^3.0.0, figures@^3.1.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^10.1.4: - version "10.1.4" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-10.1.4.tgz#1e81441517dc33ba5fe14421d96dc5fe7e37e820" - integrity sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA== +file-entry-cache@^11.1.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-11.1.1.tgz#728918c624dbeb09372276837ea0c413ec78806b" + integrity sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A== dependencies: - flat-cache "^6.1.13" + flat-cache "^6.1.19" file-entry-cache@^5.0.1: version "5.0.1" @@ -9612,14 +9641,14 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" -flat-cache@^6.1.13: - version "6.1.13" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.13.tgz#7428e97be2aa918f371e880ebbf7f61ff48f33fa" - integrity sha512-gmtS2PaUjSPa4zjObEIn4WWliKyZzYljgxODBfxugpK6q6HU9ClXzgCJ+nlcPKY9Bt090ypTOLIFWkV0jbKFjw== +flat-cache@^6.1.19: + version "6.1.19" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.19.tgz#20e5b201c9b181a7b773b3b150108932077d2bbf" + integrity sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A== dependencies: - cacheable "^1.10.4" + cacheable "^2.2.0" flatted "^3.3.3" - hookified "^1.11.0" + hookified "^1.13.0" flatted@^2.0.0: version "2.0.2" @@ -10632,6 +10661,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hashery@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hashery/-/hashery-1.2.0.tgz#a5f865f169aedd964d6e986cd56b03128df9af44" + integrity sha512-43XJKpwle72Ik5Zpam7MuzRWyNdwwdf6XHlh8wCj2PggvWf+v/Dm5B0dxGZOmddidgeO6Ofu9As/o231Ti/9PA== + dependencies: + hookified "^1.13.0" + hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -10712,10 +10748,10 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hookified@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.12.0.tgz#eb4097ed1459211eef47fe85a8b3382c5f633996" - integrity sha512-hMr1Y9TCLshScrBbV2QxJ9BROddxZ12MX9KsCtuGGy/3SmmN5H1PllKerrVlSotur9dlE8hmUKAOSa3WDzsZmQ== +hookified@^1.12.2, hookified@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.13.0.tgz#fa7f8ab04897d77eecba52f35fe29e3d1f97dbbf" + integrity sha512-6sPYUY8olshgM/1LDNW4QZQN0IqgKhtl/1C8koNZBJrKLBk3AZl6chQtNwpNztvfiApHMEwMHek5rv993PRbWw== hoopy@^0.1.4: version "0.1.4" @@ -13062,12 +13098,12 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" -keyv@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-5.5.0.tgz#0ad5037484a7e01b033df7018033b5cc9ca7884f" - integrity sha512-QG7qR2tijh1ftOvClut4YKKg1iW6cx3GZsKoGyJPxHkGWK9oJhG9P3j5deP0QQOGDowBMVQFaP+Vm4NpGYvmIQ== +keyv@^5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-5.5.4.tgz#0f26a32183a5058f93fc6e02ced6318f66e8a9ea" + integrity sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ== dependencies: - "@keyv/serialize" "^1.1.0" + "@keyv/serialize" "^1.1.1" killable@^1.0.1: version "1.0.1" @@ -16192,6 +16228,13 @@ q@^1.1.2, q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== +qified@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/qified/-/qified-0.5.2.tgz#fa6af2e48eb40d06d56a203a8aa1ab37bc00d2b5" + integrity sha512-7gJ6mxcQb9vUBOtbKm5mDevbe2uRcOEVp1g4gb/Q+oLntB3HY8eBhOYRxFI2mlDFlY1e4DOSCptzxarXRvzxCA== + dependencies: + hookified "^1.13.0" + qrcode-terminal@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz#a76a48e2610a18f97fa3a2bd532b682acff86c53" @@ -19124,10 +19167,10 @@ stylelint-config-standard@39.0.1: dependencies: stylelint-config-recommended "^17.0.0" -stylelint@16.25.0: - version "16.25.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.25.0.tgz#c3d602974f2a18fa57fadc9f3f40129b098fe4dc" - integrity sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ== +stylelint@16.26.0: + version "16.26.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.26.0.tgz#cc0ab36abe21c7d5ddb682c482ea16dc82e61b62" + integrity sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ== dependencies: "@csstools/css-parser-algorithms" "^3.0.5" "@csstools/css-tokenizer" "^3.0.4" @@ -19142,7 +19185,7 @@ stylelint@16.25.0: debug "^4.4.3" fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" - file-entry-cache "^10.1.4" + file-entry-cache "^11.1.0" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" From a999a4b63a5209f9a4eb641062eab3bc449100a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:57:58 +0000 Subject: [PATCH 39/77] fix(deps): update dependency @types/lodash to v4.17.21 (#1323) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a92eae8fbb..2fbd2372a7 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@lightningpolar/litd-api": "0.15.0-alpha.rc1", "@lightningpolar/lnd-api": "0.19.0-beta", "@lightningpolar/tapd-api": "0.6.0-alpha.rc2", - "@types/lodash": "4.17.20", + "@types/lodash": "4.17.21", "archiver": "7.0.1", "docker-compose": "0.24.0", "dockerode": "4.0.2", diff --git a/yarn.lock b/yarn.lock index 2cd0ee42d7..cf6ae1eecd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3234,10 +3234,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@4.17.20": - version "4.17.20" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93" - integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA== +"@types/lodash@4.17.21": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.21.tgz#b806831543d696b14f8112db600ea9d3a1df6ea4" + integrity sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ== "@types/lodash@^4.14.72": version "4.14.202" From b26f5659eaf4adeab4982df409825cb1b7b9f306 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 15:27:55 +0000 Subject: [PATCH 40/77] chore(deps): update dependency stylelint to v16.26.1 (#1324) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 2fbd2372a7..b70bbef066 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "standard-version": "9.5.0", "strip-ansi": "6.0.1", "styled-components": "6.1.19", - "stylelint": "16.26.0", + "stylelint": "16.26.1", "stylelint-config-prettier": "9.0.5", "stylelint-config-standard": "39.0.1", "testcafe": "3.7.2", diff --git a/yarn.lock b/yarn.lock index cf6ae1eecd..c1261fdf7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1765,6 +1765,11 @@ resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz#5755370a9a29abaec5515b43c8b3f2cf9c2e3076" integrity sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ== +"@csstools/css-syntax-patches-for-csstree@^1.0.19": + version "1.0.19" + resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.19.tgz#816f93d4cdd4e4978ccd5860e866eb1e737ddbe1" + integrity sha512-QW5/SM2ARltEhoKcmRI1LoLf3/C7dHGswwCnfLcoMgqurBT4f8GvwXMgAbK/FwcxthmJRK5MGTtddj0yQn0J9g== + "@csstools/css-tokenizer@^3.0.4": version "3.0.4" resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" @@ -9432,7 +9437,7 @@ figures@^3.0.0, figures@^3.1.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^11.1.0: +file-entry-cache@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-11.1.1.tgz#728918c624dbeb09372276837ea0c413ec78806b" integrity sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A== @@ -19167,12 +19172,13 @@ stylelint-config-standard@39.0.1: dependencies: stylelint-config-recommended "^17.0.0" -stylelint@16.26.0: - version "16.26.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.26.0.tgz#cc0ab36abe21c7d5ddb682c482ea16dc82e61b62" - integrity sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ== +stylelint@16.26.1: + version "16.26.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.26.1.tgz#7048accf9c3990dc074dff13c6f3cdc35c780c95" + integrity sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw== dependencies: "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-syntax-patches-for-csstree" "^1.0.19" "@csstools/css-tokenizer" "^3.0.4" "@csstools/media-query-list-parser" "^4.0.3" "@csstools/selector-specificity" "^5.0.0" @@ -19185,7 +19191,7 @@ stylelint@16.26.0: debug "^4.4.3" fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" - file-entry-cache "^11.1.0" + file-entry-cache "^11.1.1" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" From 0f8f611c7c6d97a2c8c0f740120910f1ef120c29 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Tue, 11 Nov 2025 22:51:14 -0600 Subject: [PATCH 41/77] feat(images): add support for LND v0.19.3-beta --- docker/README.md | 1 + docker/lnd/Dockerfile | 2 +- src/utils/constants.ts | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index 4ef2ceb791..732bdb875d 100644 --- a/docker/README.md +++ b/docker/README.md @@ -50,6 +50,7 @@ Replace `` with the desired bitcoind version (ex: `0.18.1`) ### Tags +- `0.19.3-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.2-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.1-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.0-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) diff --git a/docker/lnd/Dockerfile b/docker/lnd/Dockerfile index 29f6154daa..c28aeda94b 100644 --- a/docker/lnd/Dockerfile +++ b/docker/lnd/Dockerfile @@ -16,7 +16,7 @@ RUN SYS_ARCH="$(dpkg --print-architecture)" \ && rm *.tar.gz RUN curl -SLO https://raw.githubusercontent.com/lightningnetwork/lnd/master/contrib/lncli.bash-completion \ - && mkdir /etc/bash_completion.d \ + && mkdir -p /etc/bash_completion.d \ && mv lncli.bash-completion /etc/bash_completion.d/ \ && curl -SLO https://raw.githubusercontent.com/scop/bash-completion/master/bash_completion \ && mv bash_completion /usr/share/bash-completion/ diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 09f13db03b..857ddf6771 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -342,11 +342,12 @@ export const REPO_STATE_URL = * are pushed to Docker Hub, this list should be updated along with the /docker/nodes.json file. */ export const defaultRepoState: DockerRepoState = { - version: 75, + version: 76, images: { LND: { - latest: '0.19.2-beta', + latest: '0.19.3-beta', versions: [ + '0.19.3-beta', '0.19.2-beta', '0.19.1-beta', '0.19.0-beta', @@ -362,6 +363,7 @@ export const defaultRepoState: DockerRepoState = { // not all LND versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each LND version compatibility: { + '0.19.3-beta': '29.0', '0.19.2-beta': '29.0', '0.19.1-beta': '29.0', '0.19.0-beta': '29.0', From 20dcdd9ed6fd3484efde3cda295854996d52c909 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Tue, 11 Nov 2025 22:58:50 -0600 Subject: [PATCH 42/77] feat(images): add support for LND v0.20.0-beta --- docker/README.md | 1 + src/utils/constants.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index 732bdb875d..767e79e780 100644 --- a/docker/README.md +++ b/docker/README.md @@ -50,6 +50,7 @@ Replace `` with the desired bitcoind version (ex: `0.18.1`) ### Tags +- `0.20.0-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.3-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.2-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) - `0.19.1-beta` ([lnd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/lnd/Dockerfile)) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 857ddf6771..affb3e0850 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -345,8 +345,9 @@ export const defaultRepoState: DockerRepoState = { version: 76, images: { LND: { - latest: '0.19.3-beta', + latest: '0.20.0-beta', versions: [ + '0.20.0-beta', '0.19.3-beta', '0.19.2-beta', '0.19.1-beta', @@ -363,6 +364,7 @@ export const defaultRepoState: DockerRepoState = { // not all LND versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each LND version compatibility: { + '0.20.0-beta': '29.0', '0.19.3-beta': '29.0', '0.19.2-beta': '29.0', '0.19.1-beta': '29.0', From cd4d14fe753ce60c41e118904ddab5ebed201992 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 08:18:45 -0600 Subject: [PATCH 43/77] feat(images): add support for CLN v25.09.3 --- docker/README.md | 1 + src/utils/constants.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/README.md b/docker/README.md index 767e79e780..114f542b52 100644 --- a/docker/README.md +++ b/docker/README.md @@ -109,6 +109,7 @@ Replace `` with the desired LND version (ex: `0.7.1-beta`) ### Tags +- `25.09.3` ([clightning/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/clightning/Dockerfile)) - `25.05` ([clightning/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/clightning/Dockerfile)) - `25.02.2` ([clightning/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/clightning/Dockerfile)) - `25.02` ([clightning/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/clightning/Dockerfile)) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index affb3e0850..175e899c3f 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -380,8 +380,8 @@ export const defaultRepoState: DockerRepoState = { }, }, 'c-lightning': { - latest: '25.05', - versions: ['25.05', '25.02.2', '25.02', '24.11.1', '24.11', '24.08.1', '24.05'], + latest: '25.09.3', + versions: ['25.09.3', '25.05', '25.02.2', '25.02', '24.11.1', '24.11', '24.08.1'], }, eclair: { latest: '0.12.0', From c52ea2dab96af6a56eae4c347247eba4f99fe235 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 08:28:12 -0600 Subject: [PATCH 44/77] feat(images): add support for tapd v0.7.0-alpha --- docker/README.md | 1 + src/store/models/designer.spec.ts | 4 ++-- src/utils/constants.ts | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index 114f542b52..e00f4e0151 100644 --- a/docker/README.md +++ b/docker/README.md @@ -175,6 +175,7 @@ Replace `` with the desired Eclair version (ex: `0.3.3`). ### Tags +- `0.7.0-alpha` ([tap/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/tapd/Dockerfile)) - `0.6.1-alpha` ([tap/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/tapd/Dockerfile)) - `0.6.0-alpha` ([tap/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/tapd/Dockerfile)) - `0.5.1-alpha` ([tap/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/tapd/Dockerfile)) diff --git a/src/store/models/designer.spec.ts b/src/store/models/designer.spec.ts index 7139b18805..32e4fedd9b 100644 --- a/src/store/models/designer.spec.ts +++ b/src/store/models/designer.spec.ts @@ -622,7 +622,7 @@ describe('Designer model', () => { onCanvasDrop({ id, data: lndData, position }); const spy = jest.spyOn(store.getActions().app, 'notify'); - const tapdData = { type: 'tapd', version: tapdLatest }; + const tapdData = { type: 'tapd', version: '0.6.1-alpha' }; onCanvasDrop({ id, data: tapdData, position }); await waitFor(() => { expect(spy).toHaveBeenCalledWith( @@ -630,7 +630,7 @@ describe('Designer model', () => { message: 'Failed to add node', error: new Error( 'This network does not contain a LND v0.19.0-beta (or higher) ' + - `node which is required for tapd v${tapdLatest}`, + `node which is required for tapd v0.6.1-alpha`, ), }), ); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 175e899c3f..7866d158fe 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -396,8 +396,9 @@ export const defaultRepoState: DockerRepoState = { versions: [], }, tapd: { - latest: '0.6.1-alpha', + latest: '0.7.0-alpha', versions: [ + '0.7.0-alpha', '0.6.1-alpha', '0.6.0-alpha', '0.5.1-alpha', @@ -408,6 +409,7 @@ export const defaultRepoState: DockerRepoState = { // Not all tapd versions are compatible with all LND versions. // This mapping specifies the minimum compatible LND for each tapd version compatibility: { + '0.7.0-alpha': '0.19.0-beta', '0.6.1-alpha': '0.19.0-beta', '0.6.0-alpha': '0.19.0-beta', '0.5.1-alpha': '0.18.5-beta', From f2f4b9f3a83d8136917524d27cfbb85386153b7e Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 08:34:13 -0600 Subject: [PATCH 45/77] feat(images): add support for litd v0.15.3-alpha --- docker/README.md | 1 + src/utils/constants.ts | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index e00f4e0151..b242b56eb7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -203,6 +203,7 @@ Replace `` with the desired Tap version (ex: `0.2.0-alpha`). ### Tags +- `0.15.3-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.1-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.0-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.14.1-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 7866d158fe..2c947bbb1c 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -419,13 +419,15 @@ export const defaultRepoState: DockerRepoState = { }, }, litd: { - latest: '0.15.1-alpha', - versions: ['0.15.1-alpha', '0.15.0-alpha', '0.14.1-alpha', '0.14.0-alpha'], + latest: '0.15.3-alpha', + versions: ['0.15.3-alpha', '0.15.1-alpha', '0.15.0-alpha', '0.14.1-alpha'], + // not all litd versions are compatible with all bitcoind versions. + // this mapping specifies the highest compatible bitcoind for each litd version compatibility: { + '0.15.3-alpha': '29.0', '0.15.1-alpha': '29.0', '0.15.0-alpha': '29.0', '0.14.1-alpha': '29.0', - '0.14.0-alpha': '29.0', }, }, }, From 36a6b689e1e22ffc8b0a83ee7e808c5bf2ec2f2e Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 08:38:49 -0600 Subject: [PATCH 46/77] feat(images): add support for litd v0.16.0-alpha.rc1 --- docker/README.md | 1 + src/utils/constants.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index b242b56eb7..3f52f07bc1 100644 --- a/docker/README.md +++ b/docker/README.md @@ -203,6 +203,7 @@ Replace `` with the desired Tap version (ex: `0.2.0-alpha`). ### Tags +- `0.16.0-alpha.rc1` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.3-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.1-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.0-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 2c947bbb1c..9974f8b125 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -420,10 +420,17 @@ export const defaultRepoState: DockerRepoState = { }, litd: { latest: '0.15.3-alpha', - versions: ['0.15.3-alpha', '0.15.1-alpha', '0.15.0-alpha', '0.14.1-alpha'], + versions: [ + '0.16.0-alpha.rc1', + '0.15.3-alpha', + '0.15.1-alpha', + '0.15.0-alpha', + '0.14.1-alpha', + ], // not all litd versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each litd version compatibility: { + '0.16.0-alpha.rc1': '29.0', '0.15.3-alpha': '29.0', '0.15.1-alpha': '29.0', '0.15.0-alpha': '29.0', From 098922207c1d29adecba8ff83c2b7d83bdfc8967 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Sat, 29 Nov 2025 09:42:44 -0600 Subject: [PATCH 47/77] feat(images): add new versions to nodes.json --- docker/nodes.json | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/docker/nodes.json b/docker/nodes.json index e672b80bfc..ddb49f556f 100644 --- a/docker/nodes.json +++ b/docker/nodes.json @@ -1,9 +1,11 @@ { - "version": 75, + "version": 76, "images": { "LND": { - "latest": "0.19.2-beta", + "latest": "0.20.0-beta", "versions": [ + "0.20.0-beta", + "0.19.3-beta", "0.19.2-beta", "0.19.1-beta", "0.19.0-beta", @@ -17,6 +19,8 @@ "0.16.4-beta" ], "compatibility": { + "0.20.0-beta": "29.0", + "0.19.3-beta": "29.0", "0.19.2-beta": "29.0", "0.19.1-beta": "29.0", "0.19.0-beta": "29.0", @@ -31,8 +35,8 @@ } }, "c-lightning": { - "latest": "25.05", - "versions": ["25.05", "25.02.2", "25.02", "24.11.1", "24.11", "24.08.1", "24.05"] + "latest": "25.09.3", + "versions": ["25.09.3", "25.05", "25.02.2", "25.02", "24.11.1", "24.11", "24.08.1"] }, "eclair": { "latest": "0.12.0", @@ -47,8 +51,9 @@ "versions": [] }, "tapd": { - "latest": "0.6.1-alpha", + "latest": "0.7.0-alpha", "versions": [ + "0.7.0-alpha", "0.6.1-alpha", "0.6.0-alpha", "0.5.1-alpha", @@ -57,6 +62,7 @@ "0.3.3-alpha" ], "compatibility": { + "0.7.0-alpha": "0.19.0-beta", "0.6.1-alpha": "0.19.0-beta", "0.6.0-alpha": "0.19.0-beta", "0.5.1-alpha": "0.18.5-beta", @@ -66,13 +72,20 @@ } }, "litd": { - "latest": "0.15.1-alpha", - "versions": ["0.15.1-alpha", "0.15.0-alpha", "0.14.1-alpha", "0.14.0-alpha"], + "latest": "0.15.3-alpha", + "versions": [ + "0.16.0-alpha.rc1", + "0.15.3-alpha", + "0.15.1-alpha", + "0.15.0-alpha", + "0.14.1-alpha" + ], "compatibility": { + "0.16.0-alpha.rc1": "29.0", + "0.15.3-alpha": "29.0", "0.15.1-alpha": "29.0", "0.15.0-alpha": "29.0", - "0.14.1-alpha": "29.0", - "0.14.0-alpha": "29.0" + "0.14.1-alpha": "29.0" } } } From 467a8bfbd7255712372af3ca07c64cdbf86eac2e Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:44:24 -0600 Subject: [PATCH 48/77] feat(images): add support for Bitcoin Core v30.0 --- docker/README.md | 1 + docker/bitcoind/Dockerfile | 2 +- .../bitcoin/bitcoind/bitcoindService.spec.ts | 28 +- src/lib/bitcoin/bitcoind/bitcoindService.ts | 25 +- src/lib/bitcoin/notImplementedService.ts | 4 +- .../lightning/eclair/eclairService.spec.ts | 4 +- src/store/models/bitcoin.ts | 6 +- src/types/bitcoin-core.d.ts | 2497 ++++++++++------- src/types/index.ts | 4 +- src/utils/constants.ts | 29 +- src/utils/tests/helpers.ts | 7 +- 11 files changed, 1569 insertions(+), 1038 deletions(-) diff --git a/docker/README.md b/docker/README.md index 3f52f07bc1..987d3e6b77 100644 --- a/docker/README.md +++ b/docker/README.md @@ -21,6 +21,7 @@ $ docker buildx inspect --bootstrap ### Tags +- `30.0` ([bitcoind/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/bitcoind/Dockerfile)) - `29.0` ([bitcoind/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/bitcoind/Dockerfile)) - `28.0` ([bitcoind/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/bitcoind/Dockerfile)) - `27.0` ([bitcoind/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/bitcoind/Dockerfile)) diff --git a/docker/bitcoind/Dockerfile b/docker/bitcoind/Dockerfile index 0f0ffca6e3..04e8a071f5 100644 --- a/docker/bitcoind/Dockerfile +++ b/docker/bitcoind/Dockerfile @@ -14,7 +14,7 @@ RUN SYS_ARCH="$(uname -m)" \ && rm *.tar.gz RUN curl -SLO https://raw.githubusercontent.com/bitcoin/bitcoin/master/contrib/completions/bash/bitcoin-cli.bash \ - && mkdir /etc/bash_completion.d \ + && mkdir -p /etc/bash_completion.d \ && mv bitcoin-cli.bash /etc/bash_completion.d/bitcoin-cli.bash-completion \ && curl -SLO https://raw.githubusercontent.com/scop/bash-completion/master/bash_completion \ && mv bash_completion /usr/share/bash-completion/ diff --git a/src/lib/bitcoin/bitcoind/bitcoindService.spec.ts b/src/lib/bitcoin/bitcoind/bitcoindService.spec.ts index 16efd25a90..b02aa40860 100644 --- a/src/lib/bitcoin/bitcoind/bitcoindService.spec.ts +++ b/src/lib/bitcoin/bitcoind/bitcoindService.spec.ts @@ -1,11 +1,12 @@ import log from 'electron-log'; import BitcoinCore from 'bitcoin-core'; +import { BitcoinCoreClient } from 'types/bitcoin-core'; import { createBitcoindNetworkNode } from 'utils/network'; import { getNetwork, testNodeDocker } from 'utils/tests'; import bitcoindService from './bitcoindService'; jest.mock('bitcoin-core'); -const mockBitcoin = BitcoinCore as unknown as jest.Mock; +const mockBitcoin = BitcoinCore as unknown as jest.Mock; describe('BitcoindService', () => { const network = getNetwork(); @@ -13,7 +14,7 @@ describe('BitcoindService', () => { createBitcoindNetworkNode(network, '0.18.1', testNodeDocker), ); const node = network.nodes.bitcoin[0]; - const mockProto = BitcoinCore.prototype; + const mockProto = BitcoinCore.prototype as unknown as BitcoinCoreClient; // helper func to get the first instance created during the test const getInst = () => mockBitcoin.mock.instances[0]; @@ -23,6 +24,9 @@ describe('BitcoindService', () => { mockProto.createWallet = jest.fn().mockResolvedValue({ name: '' }); mockProto.getBlockchainInfo = jest.fn().mockResolvedValue({ blocks: 10 }); mockProto.getWalletInfo = jest.fn().mockResolvedValue({ balance: 5 }); + mockProto.getBalances = jest + .fn() + .mockResolvedValue({ mine: { trusted: 5, untrusted_pending: 0, immature: 0 } }); mockProto.getNewAddress = jest.fn().mockResolvedValue('abcdef'); mockProto.sendToAddress = jest.fn().mockResolvedValue('txid'); mockProto.generateToAddress = jest.fn().mockResolvedValue(['blockhash1']); @@ -129,36 +133,42 @@ describe('BitcoindService', () => { describe('sendFunds', () => { it('should send funds with sufficient balance', async () => { const txid = await bitcoindService.sendFunds(node, 'destaddr', 1); - expect(getInst().getWalletInfo).toBeCalledTimes(1); + expect(getInst().getBalances).toBeCalledTimes(1); expect(getInst().sendToAddress).toBeCalledWith('destaddr', 1); expect(txid).toEqual('txid'); }); it('should send funds with insufficient balance', async () => { - mockProto.getWalletInfo = jest.fn().mockResolvedValue({ balance: 0 }); + mockProto.getBalances = jest + .fn() + .mockResolvedValue({ mine: { trusted: 0, untrusted_pending: 0, immature: 0 } }); mockProto.listTransactions = jest.fn().mockResolvedValue([]); const txid = await bitcoindService.sendFunds(node, 'destaddr', 10); - expect(getInst().getWalletInfo).toBeCalledTimes(1); + expect(getInst().getBalances).toBeCalledTimes(1); expect(getInst().sendToAddress).toBeCalledWith('destaddr', 10); expect(txid).toEqual('txid'); }); it('should send funds with sufficient balance above maturity height', async () => { mockProto.getBlockchainInfo = jest.fn().mockResolvedValue({ blocks: 110 }); - mockProto.getWalletInfo = jest.fn().mockResolvedValue({ balance: 0 }); + mockProto.getBalances = jest + .fn() + .mockResolvedValue({ mine: { trusted: 0, untrusted_pending: 0, immature: 0 } }); mockProto.listTransactions = jest.fn().mockResolvedValue([{ confirmations: 101 }]); const txid = await bitcoindService.sendFunds(node, 'destaddr', 100); - expect(getInst().getWalletInfo).toBeCalledTimes(1); + expect(getInst().getBalances).toBeCalledTimes(1); expect(getInst().sendToAddress).toBeCalledWith('destaddr', 100); expect(txid).toEqual('txid'); }); it('should send funds with insufficient balance above maturity height', async () => { mockProto.getBlockchainInfo = jest.fn().mockResolvedValue({ blocks: 110 }); - mockProto.getWalletInfo = jest.fn().mockResolvedValue({ balance: 0 }); + mockProto.getBalances = jest + .fn() + .mockResolvedValue({ mine: { trusted: 0, untrusted_pending: 0, immature: 0 } }); mockProto.listTransactions = jest.fn().mockResolvedValue([{ confirmations: 10 }]); const txid = await bitcoindService.sendFunds(node, 'destaddr', 10); - expect(getInst().getWalletInfo).toBeCalledTimes(1); + expect(getInst().getBalances).toBeCalledTimes(1); expect(getInst().sendToAddress).toBeCalledWith('destaddr', 10); expect(txid).toEqual('txid'); }); diff --git a/src/lib/bitcoin/bitcoind/bitcoindService.ts b/src/lib/bitcoin/bitcoind/bitcoindService.ts index 65a09085fd..00ff128308 100644 --- a/src/lib/bitcoin/bitcoind/bitcoindService.ts +++ b/src/lib/bitcoin/bitcoind/bitcoindService.ts @@ -2,6 +2,7 @@ import logger from 'electron-log'; import BitcoinCore from 'bitcoin-core'; import { BitcoinNode } from 'shared/types'; import { BitcoinService } from 'types'; +import { BitcoinCoreClient, WalletInfoCompat } from 'types/bitcoin-core'; import { delay, waitFor } from 'utils/async'; import { bitcoinCredentials, @@ -11,9 +12,7 @@ import { } from 'utils/constants'; class BitcoindService implements BitcoinService { - // the types in the v5 release are missing many functions so we have to cast as `any` - // to prevent TS errors. - createClient(node: BitcoinNode): any { + createClient(node: BitcoinNode): BitcoinCoreClient { return new BitcoinCore({ host: `http://127.0.0.1:${node.ports.rpc}`, username: bitcoinCredentials.user, @@ -21,7 +20,7 @@ class BitcoindService implements BitcoinService { logger: this.log(), // use a long timeout due to the time it takes to mine a lot of blocks timeout: 5 * 60 * 1000, - }); + }) as unknown as BitcoinCoreClient; } async createDefaultWallet(node: BitcoinNode) { @@ -36,8 +35,17 @@ class BitcoindService implements BitcoinService { return await this.createClient(node).getBlockchainInfo(); } - async getWalletInfo(node: BitcoinNode) { - return await this.createClient(node).getWalletInfo(); + async getWalletInfo(node: BitcoinNode): Promise { + const client = this.createClient(node); + const walletInfo = await client.getWalletInfo(); + // In v30, the balance fields were deprecated in favor of the getBalances method + const balances = await client.getBalances(); + return { + ...walletInfo, + balance: balances.mine.trusted, + unconfirmed_balance: balances.mine.untrusted_pending, + immature_balance: balances.mine.immature, + }; } async getNewAddress(node: BitcoinNode) { @@ -64,8 +72,9 @@ class BitcoindService implements BitcoinService { async sendFunds(node: BitcoinNode, toAddress: string, amount: number) { const client = this.createClient(node); - const { blocks } = await this.getBlockchainInfo(node); - const { balance } = await client.getWalletInfo(); + const { blocks } = await client.getBlockchainInfo(); + const balances = await client.getBalances(); + const balance = balances.mine.trusted; // if the bitcoin node doesn't have enough coins then mine more if (balance <= amount) { await this.mineUntilMaturity(node); diff --git a/src/lib/bitcoin/notImplementedService.ts b/src/lib/bitcoin/notImplementedService.ts index 7cb687715a..be326173db 100644 --- a/src/lib/bitcoin/notImplementedService.ts +++ b/src/lib/bitcoin/notImplementedService.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { ChainInfo, WalletInfo } from 'bitcoin-core'; import { BitcoinNode } from 'shared/types'; import { BitcoinService } from 'types'; +import { ChainInfo, WalletInfoCompat } from 'types/bitcoin-core'; /** * A Bitcoin Service class whose functions are not yet implemented @@ -22,7 +22,7 @@ class NotImplementedService implements BitcoinService { `getBlockchainInfo is not implemented for ${node.implementation} nodes`, ); } - getWalletInfo(node: BitcoinNode): Promise { + getWalletInfo(node: BitcoinNode): Promise { throw new Error(`getWalletInfo is not implemented for ${node.implementation} nodes`); } getNewAddress(node: BitcoinNode): Promise { diff --git a/src/lib/lightning/eclair/eclairService.spec.ts b/src/lib/lightning/eclair/eclairService.spec.ts index e61d8e8ef5..fd2aeae86c 100644 --- a/src/lib/lightning/eclair/eclairService.spec.ts +++ b/src/lib/lightning/eclair/eclairService.spec.ts @@ -1,5 +1,5 @@ -import { WalletInfo } from 'bitcoin-core'; import bitcoindService from 'lib/bitcoin/bitcoind/bitcoindService'; +import { WalletInfoCompat } from 'types/bitcoin-core'; import { defaultRepoState } from 'utils/constants'; import { defaultStateBalances, defaultStateInfo, getNetwork } from 'utils/tests'; import { eclairService } from './'; @@ -43,7 +43,7 @@ describe('EclairService', () => { }); it('should get wallet balance', async () => { - const ballanceResponse: Partial = { + const ballanceResponse: Partial = { balance: 0.00001, unconfirmed_balance: 0, immature_balance: 0, diff --git a/src/store/models/bitcoin.ts b/src/store/models/bitcoin.ts index 58cfd28f38..6df50f30e7 100644 --- a/src/store/models/bitcoin.ts +++ b/src/store/models/bitcoin.ts @@ -1,7 +1,7 @@ -import { ChainInfo, WalletInfo } from 'bitcoin-core'; import { Action, action, Thunk, thunk } from 'easy-peasy'; import { BitcoinNode, Status } from 'shared/types'; import { StoreInjections } from 'types'; +import { ChainInfo, WalletInfoCompat } from 'types/bitcoin-core'; import { delay } from 'utils/async'; import { getNetworkBackendId } from 'utils/network'; import { prefixTranslation } from 'utils/translate'; @@ -16,7 +16,7 @@ export interface BitcoinNodeMapping { export interface BitcoinNodeModel { chainInfo?: ChainInfo; - walletInfo?: WalletInfo; + walletInfo?: WalletInfoCompat; } export interface BitcoinModel { @@ -25,7 +25,7 @@ export interface BitcoinModel { clearNodes: Action; setInfo: Action< BitcoinModel, - { node: BitcoinNode; chainInfo: ChainInfo; walletInfo: WalletInfo } + { node: BitcoinNode; chainInfo: ChainInfo; walletInfo: WalletInfoCompat } >; getInfo: Thunk; mine: Thunk< diff --git a/src/types/bitcoin-core.d.ts b/src/types/bitcoin-core.d.ts index 4814ff6552..f06b2022cc 100644 --- a/src/types/bitcoin-core.d.ts +++ b/src/types/bitcoin-core.d.ts @@ -1,1135 +1,1646 @@ -// Type definitions for bitcoin-core 2.0.0 +// Type definitions for bitcoin-core 5.0.0 // Project: https://github.com/ruimarinho/bitcoin-core // Definitions by: Joe Miyamoto // Modified by: @jamaljsr // https://github.com/ruimarinho/bitcoin-core/pull/65 +// Updated for Bitcoin Core 27.0+ compatibility -declare module 'bitcoin-core' { - export interface ClientConstructorOption { - agentOptions?: any; - headers?: boolean; - host?: string; - // eslint-disable-next-line @typescript-eslint/ban-types - logger?: Function; - network?: 'mainnet' | 'regtest' | 'testnet'; - password?: string; - port?: string | number; - ssl?: any; - timeout?: number; - username?: string; - version?: string; - } - - interface Requester { - unsupported?: any[]; - version?: any; - } - - interface Parser { - headers: boolean; - } - - type ScriptDecoded = { - asm: string; - hex: string; - type: string; - reqSigs: number; - addresses: string[]; - ps2h?: string; - }; - type FundRawTxOptions = { - changeAddress?: string; - chnagePosition?: number; - includeWatching?: boolean; - lockUnspents?: boolean; - feeRate?: number; - subtractFeeFromOutputs?: number[]; - replaceable?: boolean; - conf_target?: number; - estimate_mode: FeeEstimateMode; - }; +// Type definitions for Bitcoin Core RPC methods and responses - type FeeEstimateMode = 'UNSET' | 'ECONOMICAL' | 'CONSERVATIVE'; +interface Requester { + unsupported?: any[]; + version?: any; +} - type TxStats = { - time: number; - txcount: number; - window_final_block_hash?: string; - window_block_count?: number; - window_tx_count?: number; - window_interval?: number; - txrate: number; - }; +interface Parser { + headers: boolean; +} - type AddedNodeInfo = { - addednode: string; - connected: boolean; - addresses: { - address: string; - connected: 'inbound' | 'outbound'; - }[]; +type ScriptDecoded = { + asm: string; + hex: string; + type: string; + reqSigs: number; + addresses: string[]; + ps2h?: string; +}; +type FundRawTxOptions = { + changeAddress?: string; + chnagePosition?: number; + includeWatching?: boolean; + lockUnspents?: boolean; + feeRate?: number; + subtractFeeFromOutputs?: number[]; + replaceable?: boolean; + conf_target?: number; + estimate_mode: FeeEstimateMode; +}; + +type FeeEstimateMode = 'UNSET' | 'ECONOMICAL' | 'CONSERVATIVE'; + +type TxStats = { + time: number; + txcount: number; + window_final_block_hash?: string; + window_block_count?: number; + window_tx_count?: number; + window_interval?: number; + txrate: number; +}; + +type AddedNodeInfo = { + addednode: string; + connected: boolean; + addresses: { + address: string; + connected: 'inbound' | 'outbound'; + }[]; +}; + +type MemoryStats = { + locked: { + used: number; + free: number; + total: number; + locked: number; + chunks_used: number; + chunks_free: number; }; - - type MemoryStats = { - locked: { - used: number; - free: number; - total: number; - locked: number; - chunks_used: number; - chunks_free: number; - }; +}; + +type NetworkInfo = { + version: number; + subversion: string; + protocolversion: number; + localservices: string; + localrelay: boolean; + timeoffset: number; + connections: number; + networkactive: boolean; + networks: { + name: string; + limited: boolean; + reachable: boolean; + proxy: string; + proxy_randomize_credentials: boolean; + }[]; + relayfee: number; + incrementalfee: number; + localaddresses: { + address: string; + port: number; + score: number; + }[]; + warnings?: string; +}; + +type PeerInfo = { + id: number; + addr: string; + addrbind: string; + addrlocal: string; + services: string; + relaytxs: boolean; + lastsend: number; + lastrecv: number; + bytessent: number; + bytesrecv: number; + conntime: number; + timeoffset: number; + pingtime: number; + minping: number; + version: number; + subver: string; + inbound: boolean; + addnode: boolean; + startinheight: number; + banscore: number; + synced_headers: number; + synced_blocks: number; + inflight: number[]; + whitelisted: boolean; + bytessent_per_msg: { + [key: string]: number; }; - - type NetworkInfo = { - version: number; - subversion: string; - protocolversion: number; - localservices: string; - localrelay: boolean; - timeoffset: number; - connections: number; - networkactive: boolean; - networks: { - name: string; - limited: boolean; - reachable: boolean; - proxy: string; - proxy_randomize_credentials: boolean; - }[]; - relayfee: number; - incrementalfee: number; - localaddresses: { - address: string; - port: number; - score: number; - }[]; - warnings?: string; + byterecv_per_msg: { + [key: string]: number; }; - - type PeerInfo = { - id: number; - addr: string; - addrbind: string; - addrlocal: string; - services: string; - relaytxs: boolean; - lastsend: number; - lastrecv: number; - bytessent: number; - bytesrecv: number; - conntime: number; - timeoffset: number; - pingtime: number; - minping: number; +}; + +type NetTotals = { + totalbytesrecv: number; + totalbytessent: number; + timemlillis: number; + uploadtarget: { + timeframe: number; + target: number; + target_reached: boolean; + save_historical_blocks: boolean; + bytes_left_in_cycle: number; + time_lef_in_cycle: number; + }; +}; + +type ChainInfo = { + chain: string; + blocks: number; + headers: number; + bestblockhash: string; + difficulty: number; + mediantime: number; + verificationprogress: number; + initialblockdownload: boolean; + chainwork: string; + size_on_disk: number; + pruned: boolean; + pruneheight: number; + automatic_pruning: boolean; + prune_target_size: number; + softforks: { + id: string; version: number; - subver: string; - inbound: boolean; - addnode: boolean; - startinheight: number; - banscore: number; - synced_headers: number; - synced_blocks: number; - inflight: number[]; - whitelisted: boolean; - bytessent_per_msg: { - [key: string]: number; + reject: { + status: boolean; }; - byterecv_per_msg: { - [key: string]: number; + }[]; + bip9_softforks: { + [key: string]: { + status: 'defined' | 'started' | 'locked_in' | 'active' | 'failed'; }; + }[]; + warnings?: string; +}; +type ChainTip = { + height: number; + hash: string; + branchlen: number; + status: 'active' | 'valid-fork' | 'valid-headers' | 'headers-only' | 'invalid'; +}; +type Outpoint = { id: string; index: number }; +type UTXO = { + height: number; + value: number; + scriptPubkey: { + asm: string; + hex: string; + reqSigs: number; + type: string; + addresses: string[]; }; - - type NetTotals = { - totalbytesrecv: number; - totalbytessent: number; - timemlillis: number; - uploadtarget: { - timeframe: number; - target: number; - target_reached: boolean; - save_historical_blocks: boolean; - bytes_left_in_cycle: number; - time_lef_in_cycle: number; - }; +}; + +type UnspentTxInfo = { + txid: string; + vout: number; + address: string; + acount: string; + scriptPubKey: string; + amount: number; + confirmations: number; + redeemScript: string; + spendable: boolean; + solvable: boolean; + safe: boolean; +}; + +type PrevOut = { + txid: string; + vout: number; + scriptPubKey: string; + redeemScript?: string; + amount: number; +}; + +type UTXOStats = { + height: number; + bestblock: string; + transactions: number; + txouts: number; + bogosize: number; + hash_serialized_2: string; + disk_size: number; + total_amount: number; +}; +type MempoolContent = { + [key: string]: { + size: number; + fee: number; + modifiedfee: number; + time: number; + height: number; + descendantcount: number; + descendantsize: number; + descendantfees: number; + ancestorcount: number; + ancestorsize: number; + ancestorfees: number; + wtxid: string; + depends: string[]; }; +}; + +type DecodedRawTransaction = { + txid: string; + hash: string; + size: number; + vsize: number; + version: number; + locktime: number; + vin: TxIn[]; + vout: TxOut[]; +}; + +interface FetchedRawTransaction extends DecodedRawTransaction { + hex: string; + blockhash: string; + confirmations: number; + time: number; + blocktime: number; +} - type ChainInfo = { - chain: string; - blocks: number; - headers: number; - bestblockhash: string; - difficulty: number; - mediantime: number; - verificationprogress: number; - initialblockdownload: boolean; - chainwork: string; - size_on_disk: number; - pruned: boolean; - pruneheight: number; - automatic_pruning: boolean; - prune_target_size: number; - softforks: { - id: string; - version: number; - reject: { - status: boolean; - }; - }[]; - bip9_softforks: { - [key: string]: { - status: 'defined' | 'started' | 'locked_in' | 'active' | 'failed'; - }; - }[]; - warnings?: string; +type MiningInfo = { + blocks: number; + currentblockweight: number; + currentblocktx: number; + difficulty: number; + networkhashps: number; + pooledtx: number; + chain: 'main' | 'test' | 'regtest'; + warnings?: string; +}; + +type MempoolInfo = { + size: number; + bytes: number; + usage: number; + maxmempol: number; + mempoolminfee: number; + minrelaytxfee: number; +}; +type BlockHeader = { + hash: string; + confirmations: number; + height: number; + version: number; + versionHex: string; + merkleroot: string; + time: number; + mediantime: number; + nonce: number; + bits: string; + difficulty: number; + chainwork: string; + previoutsblockchash: string; +}; +type Block = { + hash: string; + confirmations: number; + strippedsize: number; + size: number; + weight: number; + height: number; + version: number; + verxionHex: string; + merkleroot: string; + tx: Transaction[] | string; + hex: string; + time: number; + mediantime: number; + nonce: number; + bits: string; + difficulty: number; + chainwork: string; + previousblockhash: string; + nextblockchash?: string; +}; +type Transaction = { + txid: string; + hash: string; + version: number; + size: number; + vsize: number; + locktime: number; + vin: TxIn[]; + vout: TxOut[]; +}; + +type TxIn = { + txid: string; + vout: number; + scriptSig: { + asm: string; + hex: string; }; - type ChainTip = { - height: number; - hash: string; - branchlen: number; - status: 'active' | 'valid-fork' | 'valid-headers' | 'headers-only' | 'invalid'; + txinwitness?: string[]; + sequence: number; +}; + +type TxInForCreateRaw = { + txid: string; + vout: number; + sequence?: number; +}; + +type TxOut = { + value: number; + n: number; + scriptPubKey: { + asm: string; + hex: string; + reqSigs: number; + type: scriptPubkeyType; + addresses: string[]; }; - type Outpoint = { id: string; index: number }; - type UTXO = { - height: number; - value: number; - scriptPubkey: { - asm: string; - hex: string; - reqSigs: number; - type: string; - addresses: string[]; - }; +}; + +type TxOutForCreateRaw = { + address: string; + data: string; +}; + +type TxOutInBlock = { + bestblock: string; + confirmations: number; + value: number; + scriptPubKey: { + asm: string; + hex: string; + reqSigs: number; + type: scriptPubkeyType; + addresses: string[]; }; - - type UnspentTxInfo = { - txid: string; - vout: number; + coinbase: boolean; +}; + +type DecodedScript = { + asm: string; + hex: string; + type: string; + reqSigs: number; + addresses: string[]; + p2sh: string; +}; + +type WalletTransaction = { + amount: number; + fee: number; + confirmations: number; + blockhash: string; + blockindex: number; + blocktime: number; + txid: string; + time: number; + timereceived: number; + 'bip125-replaceable': 'yes' | 'no' | 'unknown'; + details: { + account: string; address: string; - acount: string; - scriptPubKey: string; + category: 'send' | 'receive'; amount: number; - confirmations: number; - redeemScript: string; - spendable: boolean; - solvable: boolean; - safe: boolean; - }; - - type PrevOut = { + label?: string; + vout: number; + fee: number; + abandoned: number; + }[]; + hex: string; +}; + +type WalletInfo = { + walletname: string; + walletversion: number; + txcount: number; + keypoololdest: number; + keypoolsize: number; + paytxfee: number; + hdmasterkeyid: string; +}; + +// This is a compatibility type for the WalletInfo type in bitcoind v30. This includes +// the balance fields that were deprecated in favor of the getBalances method. We use +// in the BitcoinService.getWalletInfo method to return the legacy balance fields, +// avoiding a large refactoring effort. +type WalletInfoCompat = WalletInfo & { + balance: number; + unconfirmed_balance: number; + immature_balance: number; +}; + +type scriptPubkeyType = string; + +type SigHashType = + | 'ALL' + | 'NONE' + | 'SINGLE' + | 'ALL|ANYONECANPAY' + | 'NONE|ANYONECANPAY' + | 'SINGLE|ANYONECANPAY'; + +type SignRawTxResult = { + hex: string; + complete: boolean; + errors?: { txid: string; vout: number; - scriptPubKey: string; - redeemScript?: string; - amount: number; - }; - - type UTXOStats = { - height: number; - bestblock: string; - transactions: number; - txouts: number; - bogosize: number; - hash_serialized_2: string; - disk_size: number; - total_amount: number; - }; - type MempoolContent = { - [key: string]: { - size: number; - fee: number; - modifiedfee: number; - time: number; - height: number; - descendantcount: number; - descendantsize: number; - descendantfees: number; - ancestorcount: number; - ancestorsize: number; - ancestorfees: number; - wtxid: string; - depends: string[]; + scriptSig: string; + sequence: number; + error: string; + }[]; +}; + +type ValidateAddressResult = { + isvalid: boolean; + address?: string; + scriptPubKey?: string; + ismine?: boolean; + iswatchonly?: boolean; + isscript?: boolean; + script?: string; + hex?: string; + addresses?: string[]; + sigsrequired?: number; + pubkey?: string; + iscompressed?: boolean; + account?: string; + timestamp?: number; + hdkeypath?: string; + hdmasterkeyid?: string; +}; + +type ImportMultiRequest = { + scriptPubKey: string | { address: string }; + timestamp: number | 'now'; + redeemScript?: string; + pubkeys?: string[]; + keys?: string[]; + internal?: boolean; + watchonly?: boolean; + label?: string; +}; + +type Received = { + involvesWatchonly?: boolean; + account: string; + amount: number; + confirmations: number; + label: string; +}; + +type ListUnspentOptions = { + minimumAmount: number | string; + maximumAmount: number | string; + maximumCount: number | string; + minimumSumAmount: number | string; +}; + +type ReceivedByAccount = Received; + +type ReceivedByAddress = { + address: string; + txids: string[]; +} & Received; + +type RestExtension = 'json' | 'bin' | 'hex'; + +type PsbtInput = { + [key: string]: any; +}; + +type PsbtOutput = { + [key: string]: any; +}; + +type PsbtAnalyzeResult = { + inputs: { + has_utxo: boolean; + is_final: boolean; + missing: { + pubkeys: string[]; + signatures: string[]; + redeemscript?: string; + witnessscript?: string; }; + next: string; + }[]; + estimated_vsize?: number; + estimated_feerate?: number; + fee?: number; + next: string; +}; + +type DescriptorInfo = { + descriptor: string; + checksum: string; + isrange: boolean; + issolvable: boolean; + hasprivatekeys: boolean; +}; + +type ScanTxOutSetResult = { + success: boolean; + txouts: number; + height: number; + bestblock: string; + unspents: UnspentTxInfo[]; + total_amount: number; +}; + +type EnumerateSignersResult = { + signers: any[]; +}; + +type IndexInfo = { + [key: string]: { + synced: boolean; + best_block_height: number; }; +}; - type DecodedRawTransaction = { - txid: string; - hash: string; - size: number; - vsize: number; - version: number; - locktime: number; - vin: TxIn[]; - vout: TxOut[]; - }; +type RpcInfo = { + active_commands: { + method: string; + duration: number; + }[]; +}; - interface FetchedRawTransaction extends DecodedRawTransaction { - hex: string; - blockhash: string; - confirmations: number; - time: number; - blocktime: number; - } - - type MiningInfo = { - blocks: number; - currentblockweight: number; - currentblocktx: number; - difficulty: number; - networkhashps: number; - pooledtx: number; - chain: 'main' | 'test' | 'regtest'; - warnings?: string; - }; +type ChainState = { + [key: string]: any; +}; - type MempoolInfo = { - size: number; - bytes: number; - usage: number; - maxmempol: number; - mempoolminfee: number; - minrelaytxfee: number; - }; - type BlockHeader = { - hash: string; - confirmations: number; - height: number; - version: number; - versionHex: string; - merkleroot: string; - time: number; - mediantime: number; - nonce: number; - bits: string; - difficulty: number; - chainwork: string; - previoutsblockchash: string; - }; - type Block = { - hash: string; - confirmations: number; - strippedsize: number; - size: number; - weight: number; +type DeploymentInfo = { + [key: string]: { + type: string; height: number; - version: number; - verxionHex: string; - merkleroot: string; - tx: Transaction[] | string; - hex: string; - time: number; - mediantime: number; - nonce: number; - bits: string; - difficulty: number; - chainwork: string; - previousblockhash: string; - nextblockchash?: string; - }; - type Transaction = { - txid: string; - hash: string; - version: number; - size: number; - vsize: number; - locktime: number; - vin: TxIn[]; - vout: TxOut[]; + active: boolean; + hash?: string; }; +}; + +type BalanceInfo = { + trusted: number; + untrusted_pending: number; + immature: number; +}; + +type GetBalancesResult = { + mine: BalanceInfo; + watchonly?: BalanceInfo; +}; + +type GetBlockFilterResult = { + filter: string; + header: string; +}; + +type GetTxSpendingPrevOutResult = { + txid: string; + vout: number; + spendingtxid?: string; +}; + +type ImportDescriptorResult = { + success: boolean; + error?: any; +}; + +type ListDescriptorsResult = { + wallet_name: string; + descriptors: any[]; +}; + +type ListWalletDirResult = { + name: string; +}; + +type LoadTxOutSetResult = { + coins_loaded: number; + tip_hash: string; + base_height: number; + path: string; +}; + +type LoadWalletResult = { + name: string; + warning: string; +}; + +type LoggingResult = { + [key: string]: boolean; +}; + +type PsbtBumpFeeResult = { + psbt: string; + origfee: number; + fee: number; + error?: string[]; +}; + +type RescanBlockchainResult = { + start_height: number; + stop_height: number; +}; + +type RestoreWalletResult = { + name: string; + warning: string; +}; + +type SendResult = { + txid: string; + fee: number; + change: string; + change_pos: number; +}; + +type SetWalletFlagResult = { + flag_name: string; + flag_state: boolean; + warnings: string; +}; + +type TestMempoolAcceptResult = { + txid: string; + allowed: boolean; + 'reject-reason'?: string; +}; + +type UpgradeWalletResult = { + result: string; +}; + +type WalletCreateFundedPsbtResult = { + psbt: string; + fee: number; + changepos: number; +}; + +type WalletDisplayAddressResult = { + address: string; +}; + +type BumpFeeResult = { + txid: string; + origfee: number; + fee: number; + error?: string[]; +}; + +type CreateMultiSigResult = { + address: string; + redeemScript: string; +}; + +type CreateWalletResult = { + name: string; + warning: string; +}; + +type EstimateSmartFeeResult = { + feerate?: number; + errors?: string[]; + blocks?: number; +}; + +type FundRawTransactionResult = { + hex: string; + fee: number; + changepos: number; +}; + +type ImportMultiResult = { + success: boolean; + error?: { code: string; message: string }; +}; + +type ListAccountsResult = { + [key: string]: number; +}; + +type SignMessageWithPrivKeyResult = { + signature: string; +}; + +type UnspentTransactionOutputsResult = { + chainHeight: number; + chaintipHash: string; + bipmap: string; + utxos: UTXO[]; +}; + +type ListLockUnspentResult = { + txid: string; + vout: number; +}; + +type DumpTxOutsetResult = { + coins_written: number; +}; + +type FinalizePsbtResult = { + psbt?: string; + hex?: string; + complete: boolean; +}; + +type PsbtProcessResult = { + psbt: string; + complete: boolean; +}; + +type DumpWalletResult = { + filename: string; +}; + +type GetAddressesByLabelResult = { + [address: string]: any; +}; + +export type MethodNameInLowerCase = + | 'abandontransaction' + | 'abortrescan' + | 'addmultisigaddress' + | 'addnode' + | 'addwitnessaddress' + | 'analyzepsbt' + | 'backupwallet' + | 'bumpfee' + | 'clearbanned' + | 'combinepsbt' + | 'combinerawtransaction' + | 'converttopsbt' + | 'createmultisig' + | 'createpsbt' + | 'createrawtransaction' + | 'createwallet' + | 'createwalletdescriptor' + | 'createwitnessaddress' + | 'decodepsbt' + | 'decoderawtransaction' + | 'decodescript' + | 'deriveaddresses' + | 'descriptorprocesspsbt' + | 'disconnectnode' + | 'dumpprivkey' + | 'dumptxoutset' + | 'dumpwallet' + | 'encryptwallet' + | 'enumeratesigners' + | 'estimatefee' + | 'estimatepriority' + | 'estimatesmartfee' + | 'estimatesmartpriority' + | 'finalizepsbt' + | 'fundrawtransaction' + | 'generate' + | 'generatetoaddress' + | 'generatetodescriptor' + | 'getaccount' + | 'getaccountaddress' + | 'getaddednodeinfo' + | 'getaddrmaninfo' + | 'getaddressinfo' + | 'getaddressesbyaccount' + | 'getaddressesbylabel' + | 'getbalance' + | 'getbalances' + | 'getbestblockhash' + | 'getblock' + | 'getblockcount' + | 'getblockfilter' + | 'getblockfrompeer' + | 'getblockhash' + | 'getblockheader' + | 'getblockstats' + | 'getblocktemplate' + | 'getblockchaininfo' + | 'getchainstates' + | 'getchaintips' + | 'getchaintxstats' + | 'getconnectioncount' + | 'getdeploymentinfo' + | 'getdescriptorinfo' + | 'getdifficulty' + | 'getgenerate' + | 'gethashespersec' + | 'gethdkeys' + | 'getindexinfo' + | 'getinfo' + | 'getmemoryinfo' + | 'getmempoolancestors' + | 'getmempooldescendants' + | 'getmempoolentry' + | 'getmempoolinfo' + | 'getmininginfo' + | 'getnettotals' + | 'getnetworkhashps' + | 'getnetworkinfo' + | 'getnewaddress' + | 'getnodeaddresses' + | 'getpeerinfo' + | 'getprioritisedtransactions' + | 'getrawchangeaddress' + | 'getrawmempool' + | 'getrawtransaction' + | 'getreceivedbyaccount' + | 'getreceivedbyaddress' + | 'getreceivedbylabel' + | 'getrpcinfo' + | 'gettransaction' + | 'gettxout' + | 'gettxoutproof' + | 'gettxoutsetinfo' + | 'gettxspendingprevout' + | 'getunconfirmedbalance' + | 'getwalletinfo' + | 'getwork' + | 'getzmqnotifications' + | 'help' + | 'importaddress' + | 'importdescriptors' + | 'importmempool' + | 'importmulti' + | 'importprivkey' + | 'importprunedfunds' + | 'importpubkey' + | 'importwallet' + | 'joinpsbts' + | 'keypoolrefill' + | 'listaccounts' + | 'listaddressgroupings' + | 'listbanned' + | 'listdescriptors' + | 'listlabels' + | 'listlockunspent' + | 'listreceivedbyaccount' + | 'listreceivedbyaddress' + | 'listreceivedbylabel' + | 'listsinceblock' + | 'listtransactions' + | 'listunspent' + | 'listwalletdir' + | 'listwallets' + | 'loadtxoutset' + | 'loadwallet' + | 'lockunspent' + | 'logging' + | 'migratewallet' + | 'move' + | 'newkeypool' + | 'ping' + | 'preciousblock' + | 'prioritisetransaction' + | 'pruneblockchain' + | 'psbtbumpfee' + | 'removeprunedfunds' + | 'rescanblockchain' + | 'restorewallet' + | 'savemempool' + | 'scanblocks' + | 'scantxoutset' + | 'send' + | 'sendall' + | 'sendfrom' + | 'sendmany' + | 'sendrawtransaction' + | 'sendtoaddress' + | 'setaccount' + | 'setban' + | 'setgenerate' + | 'sethdseed' + | 'setlabel' + | 'setnetworkactive' + | 'settxfee' + | 'setwalletflag' + | 'signmessage' + | 'signmessagewithprivkey' + | 'signrawtransaction' + | 'signrawtransactionwithkey' + | 'signrawtransactionwithwallet' + | 'simulaterawtransaction' + | 'stop' + | 'submitblock' + | 'submitheader' + | 'submitpackage' + | 'testmempoolaccept' + | 'unloadwallet' + | 'uptime' + | 'upgradewallet' + | 'utxoupdatepsbt' + | 'validateaddress' + | 'verifychain' + | 'verifymessage' + | 'verifytxoutproof' + | 'walletcreatefundedpsbt' + | 'walletdisplayaddress' + | 'walletlock' + | 'walletpassphrase' + | 'walletpassphrasechange' + | 'walletprocesspsbt'; + +type BatchOption = { + method: MethodNameInLowerCase; + parameters: any; +}; +export type ReturnType = T extends (...args: any[]) => infer R ? R : any; + +type BumpFeeOption = { + confTarget?: number; + totalFee?: number; + replaceable?: boolean; + estimate_mode?: FeeEstimateMode; +}; + +type WalletTxBase = { + account: string; + address: string; + category: 'send' | 'receive'; + amount: number; + vout: number; + fee: number; + confirmations: number; + blockhash: string; + blockindex: number; + blocktime: number; + txid: string; + time: number; + timereceived: number; + walletconflicts: string[]; + 'bip125-replaceable': 'yes' | 'no' | 'unknown'; + abandoned?: boolean; + comment?: string; + label: string; + to?: string; +}; + +type TransactionInListSinceBlock = WalletTxBase; + +type ListSinceBlockResult = { + transactions: TransactionInListSinceBlock[]; + removed?: TransactionInListSinceBlock[]; + lastblock: string; +}; + +type ListTransactionsResult = { + trusted: boolean; + otheraccount?: string; + abandoned?: boolean; +} & WalletTxBase; + +type AddressGrouping = [string, number] | [string, number, string]; + +export default class Client { + private readonly request: any; + private readonly requests: Requester; + private readonly parser: Parser; + + constructor(clientOption?: ClientConstructorOption); + + abandonTransaction(txid: string): Promise; + + abortRescan(): Promise; + + addMultiSigAddress( + nrequired: number, + keys: string[], + account?: string, + ): Promise; + + addNode(node: string, command: 'add' | 'remove' | 'onentry'): Promise; + + addWitnessAddress(address: string): Promise; + + backupWallet(destination: string): Promise; + + bumpFee(txid: string, options?: BumpFeeOption): Promise; + + clearBanned(): Promise; + + combineRawTransaction(txs: string[]): Promise; + + command>( + methods: BatchOption[], + ): Promise>; + + createMultiSig(nrequired: number, keys: string[]): Promise; + + createRawTransaction( + inputs: TxInForCreateRaw[], + outputs: TxOutForCreateRaw, + locktime: number, + replacable: boolean, + ): Promise; + + createWallet( + wallet_name: string, + disable_private_keys?: boolean, + blank?: boolean, + passphrase?: string, + avoid_reuse?: boolean, + descriptors?: boolean, + load_on_startup?: boolean, + ): Promise; - type TxIn = { - txid: string; - vout: number; - scriptSig: { - asm: string; - hex: string; - }; - txinwitness?: string[]; - sequence: number; - }; + /** + * @deprecated + */ + createWitnessAddress(...args: any[]): void; - type TxInForCreateRaw = { - txid: string; - vout: number; - sequence?: number; - }; + decodeRawTransaction(hexstring: string): Promise; - type TxOut = { - value: number; - n: number; - scriptPubKey: { - asm: string; - hex: string; - reqSigs: number; - type: scriptPubkeyType; - addresses: string[]; - }; - }; + decodeScript(hexstring: string): Promise; - type TxOutForCreateRaw = { - address: string; - data: string; - }; + disconnectNode(address?: string, nodeid?: number): Promise; - type TxOutInBlock = { - bestblock: string; - confirmations: number; - value: number; - scriptPubKey: { - asm: string; - hex: string; - reqSigs: number; - type: scriptPubkeyType; - addresses: string[]; - }; - coinbase: boolean; - }; + dumpPrivKey(address: string): Promise; - type DecodedScript = { - asm: string; - hex: string; - type: string; - reqSigs: number; - addresses: string[]; - p2sh: string; - }; + dumpWallet(filename: string): Promise; - type WalletTransaction = { - amount: number; - fee: number; - confirmations: number; - blockhash: string; - blockindex: number; - blocktime: number; - txid: string; - time: number; - timereceived: number; - 'bip125-replaceable': 'yes' | 'no' | 'unknown'; - details: { - account: string; - address: string; - category: 'send' | 'receive'; - amount: number; - label?: string; - vout: number; - fee: number; - abandoned: number; - }[]; - hex: string; - }; + encryptWallet(passphrase: string): Promise; - type WalletInfo = { - walletname: string; - walletversion: number; - balance: number; - unconfirmed_balance: number; - immature_balance: number; - txcount: number; - keypoololdest: number; - keypoolsize: number; - paytxfee: number; - hdmasterkeyid: string; - }; + estimateFee(nblock: number): Promise; - type scriptPubkeyType = string; + /** + * @deprecated + */ + estimatePriority(...args: any[]): void; - type SigHashType = - | 'ALL' - | 'NONE' - | 'SINGLE' - | 'ALL|ANYONECANPAY' - | 'NONE|ANYONECANPAY' - | 'SINGLE|ANYONECANPAY'; + estimateSmartFee( + conf_target: number, + estimate_mode?: FeeEstimateMode, + ): Promise; - type SignRawTxResult = { - hex: string; - complete: boolean; - errors?: { - txid: string; - vout: number; - scriptSig: string; - sequence: number; - error: string; - }[]; - }; + /** + * @deprecated + */ + estimateSmartPriority(...args: any[]): void; - type ValidateAddressResult = { - isvalid: boolean; - address?: string; - scriptPubKey?: string; - ismine?: boolean; - iswatchonly?: boolean; - isscript?: boolean; - script?: string; - hex?: string; - addresses?: string[]; - sigsrequired?: number; - pubkey?: string; - iscompressed?: boolean; - account?: string; - timestamp?: number; - hdkeypath?: string; - hdmasterkeyid?: string; - }; + fundRawTransaction( + hexstring: string, + options: FundRawTxOptions, + ): Promise; - type ImportMultiRequest = { - scriptPubKey: string | { address: string }; - timestamp: number | 'now'; - redeemScript?: string; - pubkeys?: string[]; - keys?: string[]; - internal?: boolean; - watchonly?: boolean; - label?: string; - }; + generate(nblocks: number, maxtries?: number): Promise; - type Received = { - involvesWatchonly?: boolean; - account: string; - amount: number; - confirmations: number; - label: string; - }; + generateToAddress( + nblock: number, + address: string, + maxtries?: number, + ): Promise; - type ListUnspentOptions = { - minimumAmount: number | string; - maximumAmount: number | string; - maximumCount: number | string; - minimumSumAmount: number | string; - }; + /** + * @deprecated + * @param {string} address + * @returns {Promise} + */ + getAccount(address: string): Promise; - type ReceivedByAccount = Received; + /** + * @deprecated + * @param {string} account + * @returns {Promise} + */ + getAccountAddress(account: string): Promise; - type ReceivedByAddress = { - address: string; - txids: string[]; - } & Received; - - type RestExtension = 'json' | 'bin' | 'hex'; - - export type MethodNameInLowerCase = - | 'getbestblockhash' - | 'getblock' - | 'getblockchaininfo' - | 'getblockcount' - | 'getblockhash' - | 'getblockheader' - | 'getchaintips' - | 'getchaintxstats' - | 'getdifficulty' - | 'getmempoolancestors' - | 'getmempooldescendants' - | 'getmempoolentry' - | 'getmempoolinfo' - | 'getrawmempool' - | 'gettxout' - | 'gettxoutproof' - | 'gettxoutsetinfo' - | 'preciousblock' - | 'pruneblockchain' - | 'verifychain' - | 'verifytxoutproof' - | 'getinfo' - | 'getmemoryinfo' - | 'help' - | 'stop' - | 'uptime' - | 'generate' - | 'generatetoaddress' - | 'getblocktemplate' - | 'getmininginfo' - | 'getnetworkhashps' - | 'prioritisetransaction' - | 'submitblock' - | 'addnode' - | 'clearbanned' - | 'disconnectnode' - | 'getaddednodeinfo' - | 'getconnectioncount' - | 'getnettotals' - | 'getnetworkinfo' - | 'getpeerinfo' - | 'istbanned' - | 'ping' - | 'setban' - | 'setnetworkactive' - | 'combinerawtransaction' - | 'createrawtransaction' - | 'createwallet' - | 'decoderawtransaction' - | 'decodescript' - | 'fundrawtransaction' - | 'getrawtransaction' - | 'sendrawtransaction' - | 'signrawtransaction' - | 'createmultisig' - | 'estimatefee' - | 'estimatesmartfee' - | 'signmessagewithprivkey' - | 'validateaddress' - | 'verifymessage' - | 'abandontransaction' - | 'abortrescan' - | 'addmultisigaddress' - | 'addwitnessaddress' - | 'backupwallet' - | 'bumpfee' - | 'dumpprivkey' - | 'dumpwallet' - | 'encryptwallet' - | 'getaccount' - | 'getaccountaddress' - | 'getaddressesbyaccount' - | 'getbalance' - | 'getnewaddress' - | 'getrawchangeaddress' - | 'getreceivedbyaccount' - | 'getreceivedbyaddress' - | 'gettransaction' - | 'getunconfirmedbalance' - | 'getwalletinfo' - | 'importaddress' - | 'importmulti' - | 'importprivkey' - | 'importprunedfunds' - | 'importpubkey' - | 'importwallet' - | 'keypoolrefill' - | 'listaccounts' - | 'listaddressgroupings' - | 'listlockunspent' - | 'listreceivedbyaccount' - | 'listreceivedbyaddress' - | 'listsinceblock' - | 'listtransactions' - | 'listunspent' - | 'listwallets' - | 'lockunspent' - | 'move' - | 'removeprunedfunds' - | 'sendfrom' - | 'sendmany' - | 'sendtoaddress' - | 'setaccount' - | 'settxfee' - | 'signmessage'; - - type BatchOption = { - method: MethodNameInLowerCase; - parameters: any; - }; - export type ReturnType = T extends (...args: any[]) => infer R ? R : any; + getAddedNodeInfo(node?: string): Promise; - type BumpFeeOption = { - confTarget?: number; - totalFee?: number; - replaceable?: boolean; - estimate_mode?: FeeEstimateMode; - }; + /** + * @deprecated + * @param {string} account + * @returns {Promise} + */ + getAddressesByAccount(account: string): Promise; - type WalletTxBase = { - account: string; - address: string; - category: 'send' | 'receive'; - amount: number; - vout: number; - fee: number; - confirmations: number; - blockhash: string; - blockindex: number; - blocktime: number; - txid: string; - time: number; - timereceived: number; - walletconflicts: string[]; - 'bip125-replaceable': 'yes' | 'no' | 'unknown'; - abandoned?: boolean; - comment?: string; - label: string; - to?: string; - }; + getBalance( + account?: string, + minconf?: number, + include_watchonly?: boolean, + ): Promise; - type TransactionInListSinceBlock = WalletTxBase; + getBestBlockHash(): Promise; - type ListSinceBlockResult = { - transactions: TransactionInListSinceBlock[]; - removed?: TransactionInListSinceBlock[]; - lastblock: string; - }; + getBlock(blockhash: string, verbosity?: number): Promise; + + getBlockByHash(hash: string, extension: RestExtension): Promise; + + getBlockCount(): Promise; - type ListTransactionsResult = { - trusted: boolean; - otheraccount?: string; - abandoned?: boolean; - } & WalletTxBase; + getBlockHash(height: number): Promise; - type AddressGrouping = [string, number] | [string, number, string]; + getBlockHeader(hash: string, verbose?: boolean): Promise; - export default class Client { - private readonly request: any; - private readonly requests: Requester; - private readonly parser: Parser; + getBlockHeadersByHash(hash: string, extension: RestExtension): Promise; - constructor(clientOption?: ClientConstructorOption); + getBlockTemplate(...args: any[]): void; - abandonTransaction(txid: string): Promise; + getBlockchainInfo(): Promise; - abortRescan(): Promise; + getBlockchainInformation(): Promise; - addMultiSigAddress( - nrequired: number, - keys: string[], - account?: string, - ): Promise; + getChainTips(): Promise; - addNode(node: string, command: 'add' | 'remove' | 'onentry'): Promise; + getChainTxStats(nblocks?: number, blockchash?: string): Promise; - addWitnessAddress(address: string): Promise; + getConnectionCount(): Promise; - backupWallet(destination: string): Promise; + getDifficulty(): Promise; - bumpFee( - txid: string, - options?: BumpFeeOption, - ): Promise<{ txid: string; origfee: number; fee: number; error?: string[] }>; + /** + * @deprecated + */ + getGenerate(...args: any[]): void; - clearBanned(): Promise; + /** + * @deprecated + */ + getHashesPerSec(...args: any[]): void; - combineRawTransaction(txs: string[]): Promise; + /** + * @deprecated + */ + getInfo(...args: any[]): void; - command>( - methods: BatchOption[], - ): Promise>; + getMemoryInfo(mode?: 'stats' | 'mallocinfo'): Promise; - createMultiSig( - nrequired: number, - keys: string[], - ): Promise<{ address: string; redeemScript: string }>; + getMemoryPoolContent(): Promise; - createRawTransaction( - inputs: TxInForCreateRaw[], - outputs: TxOutForCreateRaw, - locktime: number, - replacable: boolean, - ): Promise; + getMemoryPoolInformation(): Promise; - createWallet( - wallet_name: string, - disable_private_keys?: boolean, - blank?: boolean, - passphrase?: string, - avoid_reuse?: boolean, - descriptors?: boolean, - load_on_startup?: boolean, - ): Promise<{ name: string; warning: string }>; + getMempoolAncestors( + txid: string, + verbose?: boolean, + ): Promise; - /** - * @deprecated - */ - createWitnessAddress(...args: any[]): void; + getMempoolDescendants( + txid: string, + verbose?: boolean, + ): Promise; - decodeRawTransaction(hexstring: string): Promise; + getMempoolEntry(txid: string): Promise; - decodeScript(hexstring: string): Promise; + getMempoolInfo(): Promise; - disconnectNode(address?: string, nodeid?: number): Promise; + getMiningInfo(): Promise; - dumpPrivKey(address: string): Promise; + getNetTotals(): Promise; - dumpWallet(filename: string): Promise<{ filename: string }>; + getNetworkHashPs(nblocks?: number, height?: number): Promise; - encryptWallet(passphrase: string): Promise; + getNetworkInfo(): Promise; - estimateFee(nblock: number): Promise; + getNewAddress(account?: string): Promise; - /** - * @deprecated - */ - estimatePriority(...args: any[]): void; + getPeerInfo(): Promise; - estimateSmartFee( - conf_target: number, - estimate_mode?: FeeEstimateMode, - ): Promise<{ feerate?: number; errors?: string[]; blocks?: number }>; + getRawChangeAddress(): Promise; - /** - * @deprecated - */ - estimateSmartPriority(...args: any[]): void; + getRawMempool(verbose?: boolean): Promise; - fundRawTransaction( - hexstring: string, - options: FundRawTxOptions, - ): Promise<{ hex: string; fee: number; changepos: number }>; + getRawTransaction( + txid: string, + verbose?: boolean, + ): Promise; - generate(nblocks: number, maxtries?: number): Promise; + /** + * @deprecated + * @param {string} account + * @param {number} minconf + * @returns {Promise} + */ + getReceivedByAccount(account: string, minconf?: number): Promise; - generateToAddress( - nblock: number, - address: string, - maxtries?: number, - ): Promise; + getReceivedByAddress(address: string, minconf?: number): Promise; - /** - * @deprecated - * @param {string} address - * @returns {Promise} - */ - getAccount(address: string): Promise; + getTransaction(txid: string, include_watchonly?: boolean): Promise; - /** - * @deprecated - * @param {string} account - * @returns {Promise} - */ - getAccountAddress(account: string): Promise; + getTransactionByHash(hash: string, extension?: RestExtension): Promise; - getAddedNodeInfo(node?: string): Promise; + getTxOut(txid: string, index: number, include_mempool?: boolean): Promise; - /** - * @deprecated - * @param {string} account - * @returns {Promise} - */ - getAddressesByAccount(account: string): Promise; + getTxOutProof(txids: string[], blockchash?: string): Promise; - getBalance( - account?: string, - minconf?: number, - include_watchonly?: boolean, - ): Promise; + getTxOutSetInfo(): Promise; - getBestBlockHash(): Promise; + getUnconfirmedBalance(): Promise; - getBlock(blockhash: string, verbosity?: number): Promise; + getUnspentTransactionOutputs( + outpoints: Outpoint[], + ): Promise; - getBlockByHash(hash: string, extension: RestExtension): Promise; + getWalletInfo(): Promise; - getBlockCount(): Promise; + /** + * @deprecated + */ + getWork(...args: any[]): void; - getBlockHash(height: number): Promise; + help(arg: void | MethodNameInLowerCase): Promise; - getBlockHeader(hash: string, verbose?: boolean): Promise; + importAddress( + script: string, + label?: string, + rescan?: boolean, + p2sh?: boolean, + ): Promise; - getBlockHeadersByHash(hash: string, extension: RestExtension): Promise; + importMulti( + requests: ImportMultiRequest[], + options?: { rescan?: boolean }, + ): Promise; - getBlockTemplate(...args: any[]): void; + importPrivKey(bitcoinprivkey: string, label?: string, rescan?: boolean): Promise; - getBlockchainInfo(): Promise; + importPrunedFunds(rawtransaction: string, txoutproof: string): Promise; - getBlockchainInformation(): Promise; + importPubKey(pubkey: string, label?: string, rescan?: boolean): Promise; - getChainTips(): Promise; + importWallet(filename: string): Promise; - getChainTxStats(nblocks?: number, blockchash?: string): Promise; + keypoolRefill(newsize?: number): Promise; - getConnectionCount(): Promise; + listAccounts( + minconf?: number, + include_watchonlly?: boolean, + ): Promise; - getDifficulty(): Promise; + listAddressGroupings(): Promise; - /** - * @deprecated - */ - getGenerate(...args: any[]): void; + listBanned(): Promise; - /** - * @deprecated - */ - getHashesPerSec(...args: any[]): void; + listLockUnspent(): Promise; - /** - * @deprecated - */ - getInfo(...args: any[]): void; + listReceivedByAccount( + minconf?: number, + include_empty?: boolean, + include_watchonly?: boolean, + ): Promise; - getMemoryInfo(mode?: 'stats' | 'mallocinfo'): Promise; + listReceivedByAddress( + minconf?: number, + include_empty?: boolean, + include_watchonly?: boolean, + ): Promise; + + listSinceBlock( + blockhash?: string, + target_confirmations?: number, + include_watchonly?: boolean, + include_removed?: boolean, + ): Promise; + + listTransactions( + account?: string, + count?: number, + skip?: number, + include_watchonly?: boolean, + ): Promise; + + listUnspent( + minconf?: number, + maxconf?: number, + address?: string[], + include_unsafe?: boolean, + query_options?: ListUnspentOptions, + ): Promise; + + listWallets(): Promise; + + lockUnspent( + unlock: boolean, + transactions?: { txid: string; vout: number }[], + ): Promise; + + /** + * @deprecated + * @param {string} fromaccout + * @param {string} toaccount + * @param {number} amount + * @param {number} dummy + * @param {string} comment + * @returns {Promise} + */ + move( + fromaccout: string, + toaccount: string, + amount: number, + dummy?: number, + comment?: string, + ): Promise; + + ping(): Promise; + + preciousBlock(blockhash: string): Promise; + + prioritiseTransaction(txid: string, dummy: 0, fee_delta: number): Promise; + + pruneBlockchain(height: number): Promise; + + removePrunedFunds(txid: string): Promise; + + /** + * @deprecated + * @param {string} fromaccount + * @param {string} toaddress + * @param {number | string} amount + * @param {number} minconf + * @param {string} comment + * @param {string} comment_to + * @returns {Promise} + */ + sendFrom( + fromaccount: string, + toaddress: string, + amount: number | string, + minconf?: number, + comment?: string, + comment_to?: string, + ): Promise; + + sendMany( + fromaccount: string, + amounts: { address: string }, + minconf?: number, + comment?: string, + subtractfeefrom?: string[], + replaeable?: boolean, + conf_target?: number, + estimate_mode?: FeeEstimateMode, + ): Promise; + + sendRawTransaction(hexstring: string, allowhighfees?: boolean): Promise; + + sendToAddress( + address: string, + amount: number, + comment?: string, + comment_to?: string, + subtreactfeefromamount?: boolean, + replaceable?: boolean, + conf_target?: number, + estimate_mode?: FeeEstimateMode, + ): Promise; + + /** + * @deprecated + * @param {string} address + * @param {string} account + * @returns {Promise} + */ + setAccount(address: string, account: string): Promise; - getMemoryPoolContent(): Promise; + setBan( + subnet: string, + command: 'add' | 'remove', + bantime?: number, + absolute?: boolean, + ): Promise; - getMemoryPoolInformation(): Promise; + /** + * @deprecated + * @param args + */ + setGenerate(...args: any[]): void; - getMempoolAncestors( - txid: string, - verbose?: boolean, - ): Promise; + setNetworkActive(state: boolean): Promise; - getMempoolDescendants( - txid: string, - verbose?: boolean, - ): Promise; + setTxFee(amount: number | string): Promise; - getMempoolEntry(txid: string): Promise; + signMessage(address: string, message: string): Promise; - getMempoolInfo(): Promise; + signMessageWithPrivKey( + privkey: string, + message: string, + ): Promise; - getMiningInfo(): Promise; + signRawTransaction( + hexstring: string, + prevtxs?: PrevOut[], + privkeys?: string[], + sighashtype?: SigHashType, + ): Promise; - getNetTotals(): Promise; + stop(): Promise; - getNetworkHashPs(nblocks?: number, height?: number): Promise; + submitBlock(hexdata: string, dummy?: any): Promise; - getNetworkInfo(): Promise; + upTime(): Promise; - getNewAddress(account?: string): Promise; + validateAddress(address: string): Promise; - getPeerInfo(): Promise; + verifyChain(checklevel?: number, nblocks?: number): Promise; - getRawChangeAddress(): Promise; + verifyMessage(address: string, signature: string, message: string): Promise; - getRawMempool(verbose?: boolean): Promise; + verifyTxOutProof(proof: string): Promise; - getRawTransaction( - txid: string, - verbose?: boolean, - ): Promise; + walletLock(passphrase: string, timeout: number): Promise; - /** - * @deprecated - * @param {string} account - * @param {number} minconf - * @returns {Promise} - */ - getReceivedByAccount(account: string, minconf?: number): Promise; + walletPassphrase(passphrase: string, timeout: number): Promise; - getReceivedByAddress(address: string, minconf?: number): Promise; + walletPassphraseChange(oldpassphrase: string, newpassphrase: string): Promise; - getTransaction(txid: string, include_watchonly?: boolean): Promise; + analyzePsbt(psbt: string): Promise; - getTransactionByHash(hash: string, extension?: RestExtension): Promise; + combinePsbt(txs: string[]): Promise; - getTxOut( - txid: string, - index: number, - include_mempool?: boolean, - ): Promise; + convertToPsbt(hexstring: string): Promise; - getTxOutProof(txids: string[], blockchash?: string): Promise; + createPsbt( + inputs: TxInForCreateRaw[], + outputs: TxOutForCreateRaw, + locktime?: number, + replacable?: boolean, + ): Promise; - getTxOutSetInfo(): Promise; + decodePsbt(psbt: string): Promise; - getUnconfirmedBalance(): Promise; + deriveAddresses(descriptor: string, range?: [number, number]): Promise; - getUnspentTransactionOutputs(outpoints: Outpoint[]): Promise<{ - chainHeight: number; - chaintipHash: string; - bipmap: string; - utxos: UTXO[]; - }>; + descriptorProcessPsbt( + psbt: string, + descriptors?: string[], + sighashtype?: SigHashType, + ): Promise; - getWalletInfo(): Promise; + dumpTxOutset(filename: string): Promise; - /** - * @deprecated - */ - getWork(...args: any[]): void; + enumerateSigners(wallet?: string): Promise; - help(arg: void | MethodNameInLowerCase): Promise; + finalizePsbt(psbt: string, extract?: boolean): Promise; - importAddress( - script: string, - label?: string, - rescan?: boolean, - p2sh?: boolean, - ): Promise; + generateToDescriptor( + num_blocks: number, + descriptor: string, + maxtries?: number, + ): Promise; - importMulti( - requests: ImportMultiRequest[], - options?: { rescan?: boolean }, - ): Promise<{ success: boolean; error?: { code: string; message: string } }[]>; + getAddrManInfo(): Promise; - importPrivKey( - bitcoinprivkey: string, - label?: string, - rescan?: boolean, - ): Promise; + getAddressInfo(address: string): Promise; - importPrunedFunds(rawtransaction: string, txoutproof: string): Promise; + getAddressesByLabel(label: string): Promise; - importPubKey(pubkey: string, label?: string, rescan?: boolean): Promise; + getBalances(): Promise; - importWallet(filename: string): Promise; + getBlockFilter(blockhash: string, filtertype?: string): Promise; - keypoolRefill(newsize?: number): Promise; + getBlockFromPeer(blockhash: string, peer_id: number): Promise; - listAccounts( - minconf?: number, - include_watchonlly?: boolean, - ): Promise<{ [key: string]: number }>; - - listAddressGroupings(): Promise; - - listBanned(): Promise; - - listLockUnspent(): Promise<{ txid: string; vout: number }[]>; - - listReceivedByAccount( - minconf?: number, - include_empty?: boolean, - include_watchonly?: boolean, - ): Promise; - - listReceivedByAddress( - minconf?: number, - include_empty?: boolean, - include_watchonly?: boolean, - ): Promise; - - listSinceBlock( - blockhash?: string, - target_confirmations?: number, - include_watchonly?: boolean, - include_removed?: boolean, - ): Promise; - - listTransactions( - account?: string, - count?: number, - skip?: number, - include_watchonly?: boolean, - ): Promise; - - listUnspent( - minconf?: number, - maxconf?: number, - address?: string[], - include_unsafe?: boolean, - query_options?: ListUnspentOptions, - ): Promise; - - listWallets(): Promise; - - lockUnspent( - unlock: boolean, - transactions?: { txid: string; vout: number }[], - ): Promise; - - /** - * @deprecated - * @param {string} fromaccout - * @param {string} toaccount - * @param {number} amount - * @param {number} dummy - * @param {string} comment - * @returns {Promise} - */ - move( - fromaccout: string, - toaccount: string, - amount: number, - dummy?: number, - comment?: string, - ): Promise; - - ping(): Promise; - - preciousBlock(blockhash: string): Promise; - - prioritiseTransaction(txid: string, dummy: 0, fee_delta: number): Promise; - - pruneBlockchain(height: number): Promise; - - removePrunedFunds(txid: string): Promise; - - /** - * @deprecated - * @param {string} fromaccount - * @param {string} toaddress - * @param {number | string} amount - * @param {number} minconf - * @param {string} comment - * @param {string} comment_to - * @returns {Promise} - */ - sendFrom( - fromaccount: string, - toaddress: string, - amount: number | string, - minconf?: number, - comment?: string, - comment_to?: string, - ): Promise; - - sendMany( - fromaccount: string, - amounts: { address: string }, - minconf?: number, - comment?: string, - subtractfeefrom?: string[], - replaeable?: boolean, - conf_target?: number, - estimate_mode?: FeeEstimateMode, - ): Promise; - - sendRawTransaction(hexstring: string, allowhighfees?: boolean): Promise; - - sendToAddress( - address: string, - amount: number, - comment?: string, - comment_to?: string, - subtreactfeefromamount?: boolean, - replaceable?: boolean, - conf_target?: number, - estimate_mode?: FeeEstimateMode, - ): Promise; - - /** - * @deprecated - * @param {string} address - * @param {string} account - * @returns {Promise} - */ - setAccount(address: string, account: string): Promise; - - setBan( - subnet: string, - command: 'add' | 'remove', - bantime?: number, - absolute?: boolean, - ): Promise; - - /** - * @deprecated - * @param args - */ - setGenerate(...args: any[]): void; - - setNetworkActive(state: boolean): Promise; - - setTxFee(amount: number | string): Promise; - - signMessage(address: string, message: string): Promise; - - signMessageWithPrivKey( - privkey: string, - message: string, - ): Promise<{ signature: string }>; - - signRawTransaction( - hexstring: string, - prevtxs?: PrevOut[], - privkeys?: string[], - sighashtype?: SigHashType, - ): Promise; - - stop(): Promise; - - submitBlock(hexdata: string, dummy?: any): Promise; - - upTime(): Promise; - - validateAddress(address: string): Promise; - - verifyChain(checklevel?: number, nblocks?: number): Promise; - - verifyMessage(address: string, signature: string, message: string): Promise; - - verifyTxOutProof(proof: string): Promise; - - walletLock(passphrase: string, timeout: number): Promise; - - walletPassphrase(passphrase: string, timeout: number): Promise; - - walletPassphraseChange(oldpassphrase: string, newpassphrase: string): Promise; - } + getBlockStats(hash_or_height: string | number, stats?: string[]): Promise; + + getChainStates(): Promise; + + getDeploymentInfo(): Promise; + + getDescriptorInfo(descriptor: string): Promise; + + getHdKeys(wallet?: string): Promise; + + getIndexInfo(): Promise; + + getNodeAddresses(count?: number): Promise; + + getPrioritisedTransactions(): Promise; + + getReceivedByLabel(account: string, minconf?: number): Promise; + + getRpcInfo(): Promise; + + getTxSpendingPrevOut(outpoints: Outpoint[]): Promise; + + getZmqNotifications(): Promise; + + importDescriptors( + requests: any[], + options?: { rescan?: boolean }, + ): Promise; + + importMempool(rawtx: string, options?: { fee?: number }): Promise; + + joinPsbts(psbts: string[]): Promise; + + listDescriptors(private?: boolean): Promise; + + listLabels(purpose?: string): Promise; + + listReceivedByLabel( + minconf?: number, + include_empty?: boolean, + include_watchonly?: boolean, + ): Promise; + + listWalletDir(): Promise; + + loadTxOutSet(filename: string): Promise; + + loadWallet(filename: string, load_on_startup?: boolean): Promise; + + logging(include?: string[], exclude?: string[]): Promise; + + migrateWallet(wallet?: string): Promise; + + newKeyPool(): Promise; + + psbtBumpFee(txid: string, options?: BumpFeeOption): Promise; + + rescanBlockchain( + start_height?: number, + stop_height?: number, + ): Promise; + + restoreWallet( + wallet_name: string, + backup_file: string, + load_on_startup?: boolean, + ): Promise; + + saveMempool(): Promise; + + scanBlocks( + scanobjects: string[], + start_height?: number, + stop_height?: number, + filtertype?: string, + options?: any, + ): Promise; + + scanTxOutSet( + action: string, + scanobjects: string[], + options?: any, + ): Promise; + + send( + outputs: any, + conf_target?: number, + estimate_mode?: FeeEstimateMode, + fee_rate?: number, + options?: any, + ): Promise; + + sendAll( + recipients: string[], + conf_target?: number, + estimate_mode?: FeeEstimateMode, + fee_rate?: number, + options?: any, + ): Promise; + + setHdSeed(newkeypool?: boolean, seed?: string): Promise; + + setLabel(address: string, label: string): Promise; + + setWalletFlag( + flag: string, + value?: boolean, + load_on_startup?: boolean, + ): Promise; + + signRawTransactionWithKey( + hexstring: string, + privkeys?: string[], + prevtxs?: PrevOut[], + sighashtype?: SigHashType, + ): Promise; + + signRawTransactionWithWallet( + hexstring: string, + prevtxs?: PrevOut[], + sighashtype?: SigHashType, + ): Promise; + + simulateRawTransaction(hexstring: string, options?: any): Promise; + + submitHeader(hexdata: string): Promise; + + submitPackage(package_hex: string[]): Promise; + + testMempoolAccept( + rawtxs: string[], + allowhighfees?: boolean, + ): Promise; + + unloadWallet(wallet?: string): Promise; + + upgradeWallet(version: number): Promise; + + utxoUpdatePsbt(psbt: string, descriptors?: string[]): Promise; + + walletCreateFundedPsbt( + inputs?: TxInForCreateRaw[], + outputs?: TxOutForCreateRaw, + locktime?: number, + options?: FundRawTxOptions, + bip32derivs?: boolean, + ): Promise; + + walletDisplayAddress(address: string): Promise; + + walletProcessPsbt( + psbt: string, + sign?: boolean, + sighashtype?: SigHashType, + bip32derivs?: boolean, + ): Promise; } + +// Type alias for the extended Bitcoin Core client with all RPC methods +export type BitcoinCoreClient = Client; diff --git a/src/types/index.ts b/src/types/index.ts index ee01a5d322..79402b7675 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,6 @@ import * as LITD from '@lightningpolar/litd-api'; import * as TAP from '@lightningpolar/tapd-api'; import { IChart } from '@mrblenny/react-flow-chart'; -import { ChainInfo, WalletInfo } from 'bitcoin-core'; import { AnyNode, BitcoinNode, @@ -18,6 +17,7 @@ import * as PLN from 'lib/lightning/types'; import * as PLIT from 'lib/litd/types'; import * as PTAP from 'lib/tap/types'; import { PolarPlatform } from 'utils/system'; +import { ChainInfo, WalletInfoCompat } from './bitcoin-core'; export interface Network { id: number; @@ -149,7 +149,7 @@ export interface BitcoinService { waitUntilOnline: (node: BitcoinNode) => Promise; createDefaultWallet: (node: BitcoinNode) => Promise; getBlockchainInfo: (node: BitcoinNode) => Promise; - getWalletInfo: (node: BitcoinNode) => Promise; + getWalletInfo: (node: BitcoinNode) => Promise; getNewAddress: (node: BitcoinNode) => Promise; connectPeers: (node: BitcoinNode) => Promise; mine: (numBlocks: number, node: BitcoinNode) => Promise; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 9974f8b125..b24e9d06da 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -211,7 +211,6 @@ export const dockerConfigs: Record = { '-zmqpubhashblock=tcp://0.0.0.0:28336', '-txindex=1', '-dnsseed=0', - '-upnp=0', '-rpcbind=0.0.0.0', '-rpcallowip=0.0.0.0/0', '-rpcport=18443', @@ -364,13 +363,13 @@ export const defaultRepoState: DockerRepoState = { // not all LND versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each LND version compatibility: { - '0.20.0-beta': '29.0', - '0.19.3-beta': '29.0', - '0.19.2-beta': '29.0', - '0.19.1-beta': '29.0', - '0.19.0-beta': '29.0', - '0.18.5-beta': '29.0', - '0.18.4-beta': '29.0', + '0.20.0-beta': '30.0', + '0.19.3-beta': '30.0', + '0.19.2-beta': '30.0', + '0.19.1-beta': '30.0', + '0.19.0-beta': '30.0', + '0.18.5-beta': '30.0', + '0.18.4-beta': '30.0', '0.18.3-beta': '27.0', '0.18.2-beta': '27.0', '0.18.1-beta': '27.0', @@ -388,8 +387,8 @@ export const defaultRepoState: DockerRepoState = { versions: ['0.12.0', '0.11.0', '0.10.0', '0.9.0'], }, bitcoind: { - latest: '29.0', - versions: ['29.0', '28.0', '27.0', '26.0'], + latest: '30.0', + versions: ['30.0', '29.0', '28.0', '27.0', '26.0'], }, btcd: { latest: '', @@ -430,11 +429,11 @@ export const defaultRepoState: DockerRepoState = { // not all litd versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each litd version compatibility: { - '0.16.0-alpha.rc1': '29.0', - '0.15.3-alpha': '29.0', - '0.15.1-alpha': '29.0', - '0.15.0-alpha': '29.0', - '0.14.1-alpha': '29.0', + '0.16.0-alpha.rc1': '30.0', + '0.15.3-alpha': '30.0', + '0.15.1-alpha': '30.0', + '0.15.0-alpha': '30.0', + '0.14.1-alpha': '30.0', }, }, }, diff --git a/src/utils/tests/helpers.ts b/src/utils/tests/helpers.ts index 537e1cbc1f..518685a4ea 100644 --- a/src/utils/tests/helpers.ts +++ b/src/utils/tests/helpers.ts @@ -110,7 +110,7 @@ export const testRepoState: DockerRepoState = { // not all LND versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each LND version compatibility: { - '0.19.2-beta': '29.0', + '0.19.2-beta': '30.0', '0.19.1-beta': '29.0', '0.19.0-beta': '29.0', '0.18.5-beta': '29.0', @@ -164,8 +164,9 @@ export const testRepoState: DockerRepoState = { versions: ['0.10.0', '0.9.0', '0.8.0', '0.7.0', '0.6.2', '0.5.0'], }, bitcoind: { - latest: '29.0', + latest: '30.0', versions: [ + '30.0', '29.0', '28.0', '27.0', @@ -213,7 +214,7 @@ export const testRepoState: DockerRepoState = { latest: '0.14.0-alpha', versions: ['0.14.0-alpha'], compatibility: { - '0.14.0-alpha': '29.0', + '0.14.0-alpha': '30.0', }, }, }, From 8e874312628be1bf794ab5c94d92b4fbabfc9f27 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 12 Nov 2025 13:04:23 -0600 Subject: [PATCH 49/77] feat(images): add support for Eclair v0.13.1 --- docker/README.md | 1 + .../lightning/eclair/eclairService.spec.ts | 23 +++++++++++++++++++ src/lib/lightning/eclair/eclairService.ts | 16 +++++++++---- src/lib/lightning/eclair/types.ts | 11 +++++++++ src/utils/constants.ts | 4 ++-- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/docker/README.md b/docker/README.md index 987d3e6b77..d3efe37b22 100644 --- a/docker/README.md +++ b/docker/README.md @@ -150,6 +150,7 @@ Replace `` with the desired c-lightning version (ex: `0.8.0`). ### Tags +- `0.13.1` ([eclair/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/eclair/Dockerfile)) - `0.12.0` ([eclair/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/eclair/Dockerfile)) - `0.11.0` ([eclair/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/eclair/Dockerfile)) - `0.10.0` ([eclair/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/eclair/Dockerfile)) diff --git a/src/lib/lightning/eclair/eclairService.spec.ts b/src/lib/lightning/eclair/eclairService.spec.ts index fd2aeae86c..f018a4b798 100644 --- a/src/lib/lightning/eclair/eclairService.spec.ts +++ b/src/lib/lightning/eclair/eclairService.spec.ts @@ -86,11 +86,20 @@ describe('EclairService', () => { announceChannel: false, }, }, + channelParams: { + localParams: { + isChannelOpener: false, + }, + channelFlags: { + announceChannel: false, + }, + }, active: [ { fundingTx: { amountSatoshis: 0, }, + fundingAmount: 0, localCommit: { spec: { toLocal: 0, @@ -159,6 +168,20 @@ describe('EclairService', () => { const actual = await eclairService.getChannels(node11); expect(actual).toEqual(expected); }); + + it('should get a list of channels for v0.13.0', async () => { + const node13 = { ...node, version: '0.13.0' }; + chanResponse.data.commitments.channelParams.localParams.isChannelOpener = true; + chanResponse.data.commitments.params.channelFlags.announceChannel = + undefined as any; + chanResponse.data.commitments.active[0].fundingAmount = 250000; + chanResponse.data.commitments.active[0].fundingTx = undefined as any; + + eclairApiMock.httpPost.mockResolvedValue([chanResponse]); + const expected = [expect.objectContaining({ pubkey: 'abcdef' })]; + const actual = await eclairService.getChannels(node13); + expect(actual).toEqual(expected); + }); }); it('should get a list of peers', async () => { diff --git a/src/lib/lightning/eclair/eclairService.ts b/src/lib/lightning/eclair/eclairService.ts index 37817d424d..78b1e1ebaf 100644 --- a/src/lib/lightning/eclair/eclairService.ts +++ b/src/lib/lightning/eclair/eclairService.ts @@ -74,8 +74,12 @@ class EclairService implements LightningService { c => c.data.commitments?.localParams?.isFunder || c.data.commitments?.localParams?.isInitiator || + // v0.9.0+ c.data.commitments?.params?.localParams?.isInitiator || - c.data.commitments?.params?.localParams?.isChannelOpener, + // v0.11.0+ + c.data.commitments?.params?.localParams?.isChannelOpener || + // v0.13.0+ + c.data.commitments?.channelParams?.localParams?.isChannelOpener, ) .filter(c => ChannelStateToStatus[c.state] !== 'Closed') .map(c => { @@ -92,11 +96,15 @@ class EclairService implements LightningService { isPrivate = c.data.commitments.channelFlags.announceChannel === false; } else { // v0.9.0+ - const { fundingTx, localCommit } = c.data.commitments.active[0]; - capacity = fundingTx.amountSatoshis.toString(10); + const { fundingTx, localCommit, fundingAmount } = c.data.commitments.active[0]; + capacity = + fundingTx?.amountSatoshis?.toString(10) || fundingAmount?.toString(10); localBalance = localCommit.spec.toLocal; remoteBalance = localCommit.spec.toRemote; - isPrivate = c.data.commitments.params.channelFlags.announceChannel === false; + isPrivate = + c.data.commitments.params?.channelFlags?.announceChannel === false || + // v0.13.0+ + c.data.commitments.channelParams?.channelFlags?.announceChannel === false; } const status = ChannelStateToStatus[c.state]; return { diff --git a/src/lib/lightning/eclair/types.ts b/src/lib/lightning/eclair/types.ts index 7bcc9e8018..53afd029e0 100644 --- a/src/lib/lightning/eclair/types.ts +++ b/src/lib/lightning/eclair/types.ts @@ -58,11 +58,22 @@ interface ChannelData { announceChannel: boolean; }; }; + // params was renamed to channelParams in v0.13.0 + channelParams: { + localParams: { + isChannelOpener: boolean; + }; + channelFlags: { + announceChannel: boolean; + }; + }; active: [ { fundingTx: { amountSatoshis: number; }; + // fundingAmount was added in v0.13.0 + fundingAmount: number; localCommit: { spec: { toLocal: number; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index b24e9d06da..94ed43f04d 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -383,8 +383,8 @@ export const defaultRepoState: DockerRepoState = { versions: ['25.09.3', '25.05', '25.02.2', '25.02', '24.11.1', '24.11', '24.08.1'], }, eclair: { - latest: '0.12.0', - versions: ['0.12.0', '0.11.0', '0.10.0', '0.9.0'], + latest: '0.13.1', + versions: ['0.13.1', '0.12.0', '0.11.0', '0.10.0', '0.9.0'], }, bitcoind: { latest: '30.0', From 520ce27b08defe15481501cc942e5de76b2343fb Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Sat, 29 Nov 2025 09:58:25 -0600 Subject: [PATCH 50/77] ci: use macos-15-intel github CI image --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 670116b8b2..54196f6f5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: node_version: [20.x] - os: [ubuntu-latest, windows-latest, macos-13] + os: [ubuntu-latest, windows-latest, macos-15-intel] steps: - name: ubuntu file watcher tweak From 2d9881c75d218272b655db33d77bdbfd77bf5fcd Mon Sep 17 00:00:00 2001 From: Jamal James <1356600+jamaljsr@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:29:14 -0600 Subject: [PATCH 51/77] Update GitHub funding configuration --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..47a7bf4746 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [jamaljsr] From a82d6174403fbf0f9d9418eadb824d164311a12d Mon Sep 17 00:00:00 2001 From: JC Brand Date: Fri, 14 Nov 2025 11:17:10 +0200 Subject: [PATCH 52/77] fix: use correct port for the litd REST endpoint --- src/components/designer/lightning/ConnectTab.tsx | 4 ++-- .../designer/lightning/LightningDetails.spec.tsx | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/designer/lightning/ConnectTab.tsx b/src/components/designer/lightning/ConnectTab.tsx index cdc1f52ec3..c7125fc449 100644 --- a/src/components/designer/lightning/ConnectTab.tsx +++ b/src/components/designer/lightning/ConnectTab.tsx @@ -135,9 +135,9 @@ const ConnectTab: React.FC = ({ node }) => { } else if (node.implementation === 'litd') { const litd = node as LitdNode; return { - restUrl: `https://127.0.0.1:${litd.ports.web}`, + restUrl: `https://127.0.0.1:${litd.ports.rest}`, restDocsUrl: 'https://lightning.engineering/api-docs/api/lit/', - grpcUrl: `127.0.0.1:${litd.ports.web}`, + grpcUrl: `127.0.0.1:${litd.ports.web}`, // external grpc is on web port grpcDocsUrl: 'https://lightning.engineering/api-docs/api/lit/', webUrl: `https://127.0.0.1:${litd.ports.web}`, credentials: { diff --git a/src/components/designer/lightning/LightningDetails.spec.tsx b/src/components/designer/lightning/LightningDetails.spec.tsx index 6c701b397d..fb6ec8cd55 100644 --- a/src/components/designer/lightning/LightningDetails.spec.tsx +++ b/src/components/designer/lightning/LightningDetails.spec.tsx @@ -466,6 +466,13 @@ describe('LightningDetails', () => { expect(getByText('500')).toBeInTheDocument(); }); + it('should display the REST Host', async () => { + const { getByText, findByText } = renderComponent(Status.Started); + fireEvent.click(await findByText('Connect')); + expect(getByText('REST Host')).toBeInTheDocument(); + expect(getByText('https://127.0.0.1:8385')).toBeInTheDocument(); + }); + it('should display the GRPC Host', async () => { const { getByText, findByText } = renderComponent(Status.Started); fireEvent.click(await findByText('Connect')); From 2e0a013c11e4f013f1a05c3d38ad6bb9a5461bee Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:49:04 -0600 Subject: [PATCH 53/77] feat(images): add support for litd v0.16.0-alpha --- docker/README.md | 2 +- docker/nodes.json | 6 +++--- src/utils/constants.ts | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docker/README.md b/docker/README.md index d3efe37b22..d710f2d16f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -205,7 +205,7 @@ Replace `` with the desired Tap version (ex: `0.2.0-alpha`). ### Tags -- `0.16.0-alpha.rc1` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) +- `0.16.0-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.3-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.1-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) - `0.15.0-alpha` ([litd/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/litd/Dockerfile)) diff --git a/docker/nodes.json b/docker/nodes.json index ddb49f556f..3d4b2a50c9 100644 --- a/docker/nodes.json +++ b/docker/nodes.json @@ -72,16 +72,16 @@ } }, "litd": { - "latest": "0.15.3-alpha", + "latest": "0.16.0-alpha", "versions": [ - "0.16.0-alpha.rc1", + "0.16.0-alpha", "0.15.3-alpha", "0.15.1-alpha", "0.15.0-alpha", "0.14.1-alpha" ], "compatibility": { - "0.16.0-alpha.rc1": "29.0", + "0.16.0-alpha": "29.0", "0.15.3-alpha": "29.0", "0.15.1-alpha": "29.0", "0.15.0-alpha": "29.0", diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 94ed43f04d..ad412b5a23 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -418,9 +418,9 @@ export const defaultRepoState: DockerRepoState = { }, }, litd: { - latest: '0.15.3-alpha', + latest: '0.16.0-alpha', versions: [ - '0.16.0-alpha.rc1', + '0.16.0-alpha', '0.15.3-alpha', '0.15.1-alpha', '0.15.0-alpha', @@ -429,7 +429,7 @@ export const defaultRepoState: DockerRepoState = { // not all litd versions are compatible with all bitcoind versions. // this mapping specifies the highest compatible bitcoind for each litd version compatibility: { - '0.16.0-alpha.rc1': '30.0', + '0.16.0-alpha': '30.0', '0.15.3-alpha': '30.0', '0.15.1-alpha': '30.0', '0.15.0-alpha': '30.0', From 4f6e3320641cb324e0e5fc19680e9b5b8ea0f985 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Sun, 2 Mar 2025 13:56:44 +0100 Subject: [PATCH 54/77] refactor: split default designer In this commit, we split the DefaultDesigner component into Network and Simulation tabs. We also added the default look for the SimulationTab. --- .../designer/default/DefaultSidebar.spec.tsx | 6 + .../designer/default/DefaultSidebar.tsx | 156 ++---------------- .../designer/default/NetworkDesignerTab.tsx | 154 +++++++++++++++++ .../default/SimulationDesignerTab.tsx | 38 +++++ src/i18n/locales/en-US.json | 14 +- 5 files changed, 221 insertions(+), 147 deletions(-) create mode 100644 src/components/designer/default/NetworkDesignerTab.tsx create mode 100644 src/components/designer/default/SimulationDesignerTab.tsx diff --git a/src/components/designer/default/DefaultSidebar.spec.tsx b/src/components/designer/default/DefaultSidebar.spec.tsx index 84c4b3b8a3..9bb114640b 100644 --- a/src/components/designer/default/DefaultSidebar.spec.tsx +++ b/src/components/designer/default/DefaultSidebar.spec.tsx @@ -126,4 +126,10 @@ describe('DefaultSidebar Component', () => { JSON.stringify({ type: 'LND', version: lndLatest }), ); }); + + it('should display the Simulation Designer Tab', () => { + const { getByText } = renderComponent(); + fireEvent.click(getByText('Simulation Designer')); + expect(getByText('Lightning Network Simulation')).toBeInTheDocument(); + }); }); diff --git a/src/components/designer/default/DefaultSidebar.tsx b/src/components/designer/default/DefaultSidebar.tsx index 44abbf024c..c432667dc8 100644 --- a/src/components/designer/default/DefaultSidebar.tsx +++ b/src/components/designer/default/DefaultSidebar.tsx @@ -1,153 +1,25 @@ -import React from 'react'; -import { CloudSyncOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; -import styled from '@emotion/styled'; -import { Button } from 'antd'; +import React, { ReactNode, useState } from 'react'; import { usePrefixedTranslation } from 'hooks'; -import { NodeImplementation } from 'shared/types'; -import { useStoreActions, useStoreState } from 'store'; -import { dockerConfigs } from 'utils/constants'; -import { getPolarPlatform } from 'utils/system'; import SidebarCard from '../SidebarCard'; -import DraggableNode from './DraggableNode'; - -const Styled = { - AddNodes: styled.h3` - margin-top: 30px; - `, - AddDesc: styled.p` - opacity: 0.5; - font-size: 12px; - `, - Nodes: styled.div` - display: flex; - flex-direction: column; - `, - NodeRow: styled.div` - display: flex; - align-items: center; - justify-content: space-between; - `, - Arrow: styled.span<{ visible?: boolean; collapsible?: boolean }>` - margin-top: ${props => (props.visible ? 20 : 0)}px; - width: 25px; - text-align: right; - - > .anticon { - opacity: 0.4; - display: ${props => (props.collapsible ? 'inline' : 'none')}; - cursor: pointer; - - &:hover { - opacity: 1; - } - } - `, - UpdatesButton: styled(Button)` - margin-top: 30px; - `, -}; +import NetworkDesignerTab from './NetworkDesignerTab'; +import SimulationDesignerTab from './SimulationDesignerTab'; const DefaultSidebar: React.FC = () => { const { l } = usePrefixedTranslation('cmps.designer.default.DefaultSidebar'); - - const { showImageUpdates } = useStoreActions(s => s.modals); - const { settings, dockerRepoState } = useStoreState(s => s.app); - const currPlatform = getPolarPlatform(); - - const [expanded, setExpanded] = React.useState([]); - const toggleExpanded = (type: NodeImplementation) => { - if (expanded.includes(type)) { - setExpanded(expanded.filter(t => t !== type)); - } else { - setExpanded([...expanded, type]); - } + const [activeTab, setActiveTab] = useState('network'); + + const tabHeaders = [ + { key: 'network', tab: l('networkTabTitle') }, + { key: 'simulation', tab: l('simulationTabTitle') }, + ]; + const tabContents: Record = { + network: , + simulation: , }; - const toggleModal = () => showImageUpdates(); - - const nodes: { - label: string; - logo: string; - version: string; - type: NodeImplementation; - collapsible: boolean; - visible: boolean; - customId?: string; - }[] = []; - - // add custom nodes - settings.nodeImages.custom.forEach(image => { - const { logo, platforms } = dockerConfigs[image.implementation]; - const { latest } = dockerRepoState.images[image.implementation]; - if (!platforms.includes(currPlatform)) return; - nodes.push({ - label: image.name, - logo, - version: latest, - type: image.implementation, - collapsible: false, - customId: image.id, - visible: true, - }); - }); - - // add managed nodes - Object.entries(dockerRepoState.images).forEach(([key, entry]) => { - const type = key as NodeImplementation; - const { name, logo, platforms } = dockerConfigs[type as NodeImplementation]; - if (!platforms.includes(currPlatform)) return; - if (!entry.latest) return; - - nodes.push({ - label: `${name} v${entry.latest}`, - logo, - version: entry.latest, - type, - collapsible: entry.versions.length > 1, - visible: true, - }); - entry.versions - .filter(v => v != entry.latest) - .forEach(version => { - const label = `${name} v${version}`; - const collapsible = false; - const visible = expanded.includes(type); - nodes.push({ label, logo, version, collapsible, visible, type }); - }); - }); return ( - -

{l('mainDesc')}

- {l('addNodesTitle')} - {l('addNodesDesc')} - - {nodes.map(({ label, logo, version, type, collapsible, visible, customId }) => ( - - - - {expanded.includes(type) ? ( - toggleExpanded(type)} /> - ) : ( - toggleExpanded(type)} /> - )} - - - ))} - - } - onClick={toggleModal} - > - {l('checkUpdates')} - + + {tabContents[activeTab]} ); }; diff --git a/src/components/designer/default/NetworkDesignerTab.tsx b/src/components/designer/default/NetworkDesignerTab.tsx new file mode 100644 index 0000000000..d10079add1 --- /dev/null +++ b/src/components/designer/default/NetworkDesignerTab.tsx @@ -0,0 +1,154 @@ +import React from 'react'; +import { CloudSyncOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; +import styled from '@emotion/styled'; +import { Button } from 'antd'; +import { usePrefixedTranslation } from 'hooks'; +import { NodeImplementation } from 'shared/types'; +import { useStoreActions, useStoreState } from 'store'; +import { dockerConfigs } from 'utils/constants'; +import { getPolarPlatform } from 'utils/system'; +import DraggableNode from './DraggableNode'; + +const Styled = { + AddNodes: styled.h3` + margin-top: 30px; + `, + AddDesc: styled.p` + opacity: 0.5; + font-size: 12px; + `, + Nodes: styled.div` + display: flex; + flex-direction: column; + `, + NodeRow: styled.div` + display: flex; + align-items: center; + justify-content: space-between; + `, + Arrow: styled.span<{ visible?: boolean; collapsible?: boolean }>` + margin-top: ${props => (props.visible ? 20 : 0)}px; + width: 25px; + text-align: right; + + > .anticon { + opacity: 0.4; + display: ${props => (props.collapsible ? 'inline' : 'none')}; + cursor: pointer; + + &:hover { + opacity: 1; + } + } + `, + UpdatesButton: styled(Button)` + margin-top: 30px; + `, +}; + +const NetworkDesignerTab: React.FC = () => { + const { l } = usePrefixedTranslation('cmps.designer.default.NetworkDesignerTab'); + + const { showImageUpdates } = useStoreActions(s => s.modals); + const { settings, dockerRepoState } = useStoreState(s => s.app); + const currPlatform = getPolarPlatform(); + + const [expanded, setExpanded] = React.useState([]); + const toggleExpanded = (type: NodeImplementation) => { + if (expanded.includes(type)) { + setExpanded(expanded.filter(t => t !== type)); + } else { + setExpanded([...expanded, type]); + } + }; + const toggleModal = () => showImageUpdates(); + + const nodes: { + label: string; + logo: string; + version: string; + type: NodeImplementation; + collapsible: boolean; + visible: boolean; + customId?: string; + }[] = []; + + // add custom nodes + settings.nodeImages.custom.forEach(image => { + const { logo, platforms } = dockerConfigs[image.implementation]; + const { latest } = dockerRepoState.images[image.implementation]; + if (!platforms.includes(currPlatform)) return; + nodes.push({ + label: image.name, + logo, + version: latest, + type: image.implementation, + collapsible: false, + customId: image.id, + visible: true, + }); + }); + + // add managed nodes + Object.entries(dockerRepoState.images).forEach(([key, entry]) => { + const type = key as NodeImplementation; + const { name, logo, platforms } = dockerConfigs[type as NodeImplementation]; + if (!platforms.includes(currPlatform)) return; + if (!entry.latest) return; + + nodes.push({ + label: `${name} v${entry.latest}`, + logo, + version: entry.latest, + type, + collapsible: entry.versions.length > 1, + visible: true, + }); + entry.versions + .filter(v => v != entry.latest) + .forEach(version => { + const label = `${name} v${version}`; + const collapsible = false; + const visible = expanded.includes(type); + nodes.push({ label, logo, version, collapsible, visible, type }); + }); + }); + + return ( + <> +

{l('mainDesc')}

+ {l('addNodesTitle')} + {l('addNodesDesc')} + + {nodes.map(({ label, logo, version, type, collapsible, visible, customId }) => ( + + + + {expanded.includes(type) ? ( + toggleExpanded(type)} /> + ) : ( + toggleExpanded(type)} /> + )} + + + ))} + + } + onClick={toggleModal} + > + {l('checkUpdates')} + + + ); +}; + +export default NetworkDesignerTab; diff --git a/src/components/designer/default/SimulationDesignerTab.tsx b/src/components/designer/default/SimulationDesignerTab.tsx new file mode 100644 index 0000000000..20b6d07036 --- /dev/null +++ b/src/components/designer/default/SimulationDesignerTab.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import styled from '@emotion/styled'; +import { usePrefixedTranslation } from 'hooks'; +import { Button, Empty } from 'antd'; +import { Tooltip } from 'antd'; +import { PlusOutlined } from '@ant-design/icons'; + +const Styled = { + Title: styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; + font-weight: bold; + `, +}; + +const SimulationDesignerTab: React.FC = () => { + const { l } = usePrefixedTranslation('cmps.designer.default.SimulationDesignerTab'); + + return ( +
+ + {l('title')} + + + +
+ ); +}; + +export default SimulationDesignerTab; diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index d6c21edecb..209d3f1e53 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -112,11 +112,15 @@ "cmps.designer.bitcoind.actions.SendOnChainModal.balanceError": "Amount must be less than the {{backendName}} balance of {{balance}} BTC", "cmps.designer.bitcoind.actions.SendOnChainModal.successTitle": "Successfully sent {{amount}} BTC", "cmps.designer.bitcoind.actions.SendOnChainModal.successDesc": "Transaction ID: {{txid}}", - "cmps.designer.default.DefaultSidebar.title": "Network Designer", - "cmps.designer.default.DefaultSidebar.mainDesc": "Click on an element in the designer to see details", - "cmps.designer.default.DefaultSidebar.addNodesTitle": "Add Nodes", - "cmps.designer.default.DefaultSidebar.addNodesDesc": "Drag a node below onto the canvas to add it to the network", - "cmps.designer.default.DefaultSidebar.checkUpdates": "Check for new Node Versions", + "cmps.designer.default.DefaultSidebar.networkTabTitle": "Network Designer", + "cmps.designer.default.NetworkDesignerTab.mainDesc": "Click on an element in the designer to see details", + "cmps.designer.default.NetworkDesignerTab.addNodesTitle": "Add Nodes", + "cmps.designer.default.NetworkDesignerTab.addNodesDesc": "Drag a node below onto the canvas to add it to the network", + "cmps.designer.default.NetworkDesignerTab.checkUpdates": "Check for new Node Versions", + "cmps.designer.default.DefaultSidebar.simulationTabTitle": "Simulation Designer", + "cmps.designer.default.SimulationDesignerTab.createBtn": "Add a new Simulation", + "cmps.designer.default.SimulationDesignerTab.title": "Lightning Network Simulation", + "cmps.designer.default.SimulationDesignerTab.emptyMsg": "No simulations created yet", "cmps.designer.default.ImageUpdatesModal.title": "Check for new Node Versions", "cmps.designer.default.ImageUpdatesModal.updatesTitle": "There are new node versions available", "cmps.designer.default.ImageUpdatesModal.updatesDesc": "Add the new versions to begin using them in your Lightning networks.", From 93c9618029595c2082aaf5834841c4872b346e93 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Sun, 2 Mar 2025 17:56:42 +0100 Subject: [PATCH 55/77] feat: add simulation config modal --- src/components/designer/NetworkDesigner.tsx | 3 + .../designer/default/AddSimulationModal.tsx | 116 ++++++++++++++++++ .../default/SimulationDesignerTab.tsx | 15 ++- src/i18n/locales/en-US.json | 8 ++ src/store/models/modals.ts | 32 +++++ 5 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 src/components/designer/default/AddSimulationModal.tsx diff --git a/src/components/designer/NetworkDesigner.tsx b/src/components/designer/NetworkDesigner.tsx index 04a16fba4d..66ba288d4f 100644 --- a/src/components/designer/NetworkDesigner.tsx +++ b/src/components/designer/NetworkDesigner.tsx @@ -27,6 +27,7 @@ import { NewAddressModal, SendAssetModal, } from './tap/actions'; +import AddSimulationModal from './default/AddSimulationModal'; const Styled = { Designer: styled.div` @@ -67,6 +68,7 @@ const NetworkDesigner: React.FC = ({ network, updateStateDelay = 3000 }) changeTapBackend, renameNode, addLncSession, + addSimulation, } = useStoreState(s => s.modals); const { save } = useStoreActions(s => s.network); @@ -117,6 +119,7 @@ const NetworkDesigner: React.FC = ({ network, updateStateDelay = 3000 }) {sendAsset.visible && } {renameNode.visible && } {addLncSession.visible && } + {addSimulation.visible && } ); }; diff --git a/src/components/designer/default/AddSimulationModal.tsx b/src/components/designer/default/AddSimulationModal.tsx new file mode 100644 index 0000000000..7047131a11 --- /dev/null +++ b/src/components/designer/default/AddSimulationModal.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { Modal, Form, Alert, Row, Col, InputNumber } from 'antd'; +import { useStoreActions } from 'store'; +import { useStoreState } from 'store'; +import { usePrefixedTranslation } from 'hooks'; +import LightningNodeSelect from 'components/common/form/LightningNodeSelect'; +import { Status } from 'shared/types'; +import { Network } from 'types'; +import styled from '@emotion/styled'; + +interface Props { + network: Network; +} + +const Styled = { + FormItem: styled(Form.Item)` + width: 100%; + `, + InputNumber: styled(InputNumber)` + width: 100%; + `, +}; + +const AddSimulationModal: React.FC = ({ network }) => { + const { l } = usePrefixedTranslation('cmps.designer.default.AddSimulationModal'); + + const { nodes } = useStoreState(s => s.lightning); + + const [form] = Form.useForm(); + const { visible } = useStoreState(s => s.modals.addSimulation); + const { hideAddSimulation } = useStoreActions(s => s.modals); + + const selectedSource = Form.useWatch('source', form) || ''; + const selectedDestination = Form.useWatch('destination', form) || ''; + const isSameNode = selectedSource === selectedDestination; + + return ( + hideAddSimulation()} + destroyOnClose + cancelText={l('cancelBtn')} + okText={l('createBtn')} + okButtonProps={{ + disabled: isSameNode, + }} + > +
+ {isSameNode && } + + + + + + + + + + + + + `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} + parser={v => parseInt(`${v}`.replace(/(undefined|,*)/g, ''))} + /> + + + + + `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} + parser={v => parseInt(`${v}`.replace(/(undefined|,*)/g, ''))} + /> + + + + +
+ ); +}; + +export default AddSimulationModal; diff --git a/src/components/designer/default/SimulationDesignerTab.tsx b/src/components/designer/default/SimulationDesignerTab.tsx index 20b6d07036..1f064e63b2 100644 --- a/src/components/designer/default/SimulationDesignerTab.tsx +++ b/src/components/designer/default/SimulationDesignerTab.tsx @@ -4,6 +4,7 @@ import { usePrefixedTranslation } from 'hooks'; import { Button, Empty } from 'antd'; import { Tooltip } from 'antd'; import { PlusOutlined } from '@ant-design/icons'; +import { useStoreActions } from 'store'; const Styled = { Title: styled.div` @@ -18,16 +19,26 @@ const Styled = { const SimulationDesignerTab: React.FC = () => { const { l } = usePrefixedTranslation('cmps.designer.default.SimulationDesignerTab'); + const { showAddSimulation } = useStoreActions(s => s.modals); + return (
{l('title')} - diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 209d3f1e53..b4b6f02161 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -121,6 +121,14 @@ "cmps.designer.default.SimulationDesignerTab.createBtn": "Add a new Simulation", "cmps.designer.default.SimulationDesignerTab.title": "Lightning Network Simulation", "cmps.designer.default.SimulationDesignerTab.emptyMsg": "No simulations created yet", + "cmps.designer.default.AddSimulationModal.title": "Add Simulation", + "cmps.designer.default.AddSimulationModal.cancelBtn": "Cancel", + "cmps.designer.default.AddSimulationModal.createBtn": "Create", + "cmps.designer.default.AddSimulationModal.source": "Source", + "cmps.designer.default.AddSimulationModal.destination": "Destination", + "cmps.designer.default.AddSimulationModal.interval": "Interval (secs)", + "cmps.designer.default.AddSimulationModal.amount": "Amount (sat)", + "cmps.designer.default.AddSimulationModal.sameNodesWarnMsg": "Cannot create a simulation with the same node for both source and destination", "cmps.designer.default.ImageUpdatesModal.title": "Check for new Node Versions", "cmps.designer.default.ImageUpdatesModal.updatesTitle": "There are new node versions available", "cmps.designer.default.ImageUpdatesModal.updatesDesc": "Add the new versions to begin using them in your Lightning networks.", diff --git a/src/store/models/modals.ts b/src/store/models/modals.ts index f537cac8d7..c8e5097889 100644 --- a/src/store/models/modals.ts +++ b/src/store/models/modals.ts @@ -110,6 +110,15 @@ interface AddLncSessionModel { pairingPhrase?: string; } +interface AddSimulationModel { + visible: boolean; + // form values entered by the user + source?: string; + destination?: string; + interval?: number; + amount?: number; +} + export interface ModalsModel { openChannel: OpenChannelModel; changeBackend: ChangeBackendModel; @@ -127,6 +136,7 @@ export interface ModalsModel { lncSessionInfo: LncSessionInfoModel; addLncSession: AddLncSessionModel; changeTapBackend: ChangeTapBackendModel; + addSimulation: AddSimulationModel; setOpenChannel: Action; showOpenChannel: Thunk, StoreInjections>; hideOpenChannel: Thunk; @@ -184,6 +194,9 @@ export interface ModalsModel { setAddLncSession: Action; showAddLncSession: Thunk, StoreInjections>; hideAddLncSession: Thunk; + setAddSimulation: Action; + showAddSimulation: Thunk, StoreInjections>; + hideAddSimulation: Thunk; } const modalsModel: ModalsModel = { @@ -204,6 +217,7 @@ const modalsModel: ModalsModel = { renameNode: { visible: false }, lncSessionInfo: { visible: false }, addLncSession: { visible: false }, + addSimulation: { visible: false }, // reducer actions (mutations allowed thx to immer) setOpenChannel: action((state, payload) => { state.openChannel = { @@ -492,6 +506,24 @@ const modalsModel: ModalsModel = { nodeName: undefined, }); }), + setAddSimulation: action((state, payload) => { + state.addSimulation = { + ...state.addSimulation, + ...payload, + }; + }), + showAddSimulation: thunk(actions => { + actions.setAddSimulation({ visible: true }); + }), + hideAddSimulation: thunk(actions => { + actions.setAddSimulation({ + visible: false, + source: undefined, + destination: undefined, + interval: undefined, + amount: undefined, + }); + }), }; export default modalsModel; From d14d0d8f6f37c5c78142350b992709b59c1d87de Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Tue, 20 May 2025 11:03:19 +0100 Subject: [PATCH 56/77] feat: add Dockerfile for simln --- docker/simln/Dockerfile | 76 +++++++++++++++++++++++++++++++ docker/simln/docker-entrypoint.sh | 41 +++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 docker/simln/Dockerfile create mode 100644 docker/simln/docker-entrypoint.sh diff --git a/docker/simln/Dockerfile b/docker/simln/Dockerfile new file mode 100644 index 0000000000..51e11f9c32 --- /dev/null +++ b/docker/simln/Dockerfile @@ -0,0 +1,76 @@ +######################### +# Original Source: https://github.com/bitcoin-dev-project/sim-ln/blob/main/docker/Dockerfile + +# Use the rust image as the base image for the build stage +FROM rust:1.85.0 AS base + +# buildkit will provide this automatically, no need to pass it in +ARG TARGETARCH +######################### + +#################### Polar Modification +# The version of sim-ln to use +ARG SIMLN_VERSION +#################### + +FROM base AS builder-amd64 +ENV TARGET_RUST_ARCH="x86_64-unknown-linux-musl" + +FROM base AS builder-arm64 +ENV TARGET_RUST_ARCH="aarch64-unknown-linux-musl" +RUN apt-get update \ + && apt-get install clang llvm -y --no-install-recommends \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* +ENV CC_aarch64_unknown_linux_musl=clang +ENV AR_aarch64_unknown_linux_musl=llvm-ar +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" + +FROM builder-${TARGETARCH} AS builder +RUN echo "Building for architecture: ${TARGET_RUST_ARCH}" + +#################### Polar Modification +# Download the simln source code +RUN curl -SLO https://github.com/bitcoin-dev-project/sim-ln/archive/refs/tags/v${SIMLN_VERSION}.tar.gz \ + && tar -xzf *.tar.gz -C . \ + && mv sim-ln-${SIMLN_VERSION} /sim-ln \ + && rm *.tar.gz +#################### +# Install the dependencies required for building sim-ln +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + protobuf-compiler musl-tools build-essential perl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Set to 1 to instruct openssl-sys to link OpenSSL statically, ensuring a fully static binary +ENV OPENSSL_STATIC=1 +# Set to 1 to enable vendoring, making openssl-sys build OpenSSL from source instead of using system libraries +ENV OPENSSL_VENDORED=1 + +RUN rustup target add ${TARGET_RUST_ARCH} +RUN rustup component add rustfmt +RUN cd /sim-ln && RUSTFLAGS='-C target-feature=+crt-static' cargo build --locked --release --target=${TARGET_RUST_ARCH} +RUN mv /sim-ln/target/${TARGET_RUST_ARCH}/release/sim-cli /sim-ln/sim-cli + +# Use a new stage with a smaller base image to reduce image size +FROM alpine:latest + +RUN apk update && apk upgrade + +# Copy the sim-cli binaries from the build stage to the new stage +COPY --from=builder /sim-ln/sim-cli /usr/local/bin/ + +#################### Polar Modification +# Original lines: +# COPY entrypoint.sh /entrypoint.sh +# Copy the entrypoint script to the container +COPY docker-entrypoint.sh /entrypoint.sh +#################### + +RUN chmod +x entrypoint.sh + +STOPSIGNAL SIGINT + +ENTRYPOINT [ "/entrypoint.sh" ] + diff --git a/docker/simln/docker-entrypoint.sh b/docker/simln/docker-entrypoint.sh new file mode 100644 index 0000000000..c83e349a0c --- /dev/null +++ b/docker/simln/docker-entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +#################### +# Original Source: https://github.com/bitcoin-dev-project/sim-ln/blob/main/docker/entrypoint.sh +#################### + +# Define the start command +START_COMMAND="/usr/local/bin/sim-cli --sim-file $SIMFILE_PATH" + +# Check if a custom data directory was provided +if [[ ! -z ${DATA_DIR} ]]; then + START_COMMAND="$START_COMMAND --data-dir $DATA_DIR" +fi + +# Check for version arg +if [[ ! -z ${VERSION} ]]; then + START_COMMAND="$START_COMMAND --version" +fi + +# Check for help arg +if [[ ! -z ${HELP} ]]; then + START_COMMAND="$START_COMMAND --help" +fi + +# Check for log level arg +if [[ ! -z ${LOG_LEVEL} ]]; then + START_COMMAND="$START_COMMAND --log-level $LOG_LEVEL" +fi + +# Check for total time arg +if [[ ! -z ${TOTAL_TIME} ]]; then + START_COMMAND="$START_COMMAND --total-time $TOTAL_TIME" +fi + +# Check for print-batch-size arg +if [[ ! -z ${PRINT_BATCH_SIZE} ]]; then + START_COMMAND="$START_COMMAND --print-batch-size $PRINT_BATCH_SIZE" +fi + +# start the container +exec $START_COMMAND \ No newline at end of file From bbd8d350b0eac231f5f32fb1c0dc160212bff115 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Mon, 3 Mar 2025 22:42:09 +0100 Subject: [PATCH 57/77] feat: add simln to docker configs In this commit, we add simln and its related configurations to the docker. --- src/lib/docker/composeFile.ts | 10 +- src/lib/docker/dockerService.ts | 121 +++++++++++++++++++++++- src/lib/docker/nodeTemplates.ts | 21 ++++ src/shared/types.ts | 2 + src/types/index.ts | 33 +++++++ src/utils/config.ts | 4 +- src/utils/constants.ts | 20 +++- src/utils/network.ts | 4 + src/utils/tests/renderWithProviders.tsx | 3 + 9 files changed, 212 insertions(+), 6 deletions(-) diff --git a/src/lib/docker/composeFile.ts b/src/lib/docker/composeFile.ts index 54437ee579..a1e8497068 100644 --- a/src/lib/docker/composeFile.ts +++ b/src/lib/docker/composeFile.ts @@ -14,7 +14,7 @@ import { litdCredentials, } from 'utils/constants'; import { getContainerName, getDefaultCommand } from 'utils/network'; -import { bitcoind, clightning, eclair, litd, lnd, tapd } from './nodeTemplates'; +import { bitcoind, clightning, eclair, litd, lnd, tapd, simln } from './nodeTemplates'; export interface ComposeService { image: string; @@ -51,6 +51,7 @@ class ComposeFile { environment: { USERID: '${USERID:-1000}', GROUPID: '${GROUPID:-1000}', + ...service.environment, }, stop_grace_period: '30s', ...service, @@ -194,6 +195,13 @@ class ComposeFile { this.addService(svc); } + addSimln(networkId: number) { + const { name, imageName, command, env } = dockerConfigs.simln; + const containerName = `polar-n${networkId}-simln`; + const svc = simln(name, containerName, imageName, command, { ...env }); + this.addService(svc); + } + private mergeCommand(command: string, variables: Record) { let merged = command; Object.keys(variables).forEach(key => { diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 17ec369dda..047f367595 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -18,7 +18,14 @@ import { TapdNode, } from 'shared/types'; import stripAnsi from 'strip-ansi'; -import { DockerLibrary, DockerVersions, Network, NetworksFile } from 'types'; +import { + DockerLibrary, + DockerVersions, + Network, + NetworksFile, + ActivityConfig, + SimulationNodeConfig, +} from 'types'; import { legacyDataPath, networksPath, nodePath } from 'utils/config'; import { APP_VERSION, dockerConfigs } from 'utils/constants'; import { exists, read, renameFile, rm, write } from 'utils/files'; @@ -162,6 +169,10 @@ class DockerService implements DockerLibrary { } }); + if (network.simulation) { + file.addSimln(network.id); + } + const yml = yaml.dump(file.content); const path = join(network.path, 'docker-compose.yml'); await write(path, yml); @@ -387,6 +398,114 @@ class DockerService implements DockerLibrary { } } } + + /** + * Constructs the contents of sim.json file for the simulation + * + * @param network the network to start + */ + constructSimJson(network: Network) { + const simJson: { + nodes: SimulationNodeConfig[]; + activity: ActivityConfig[]; + } = { + nodes: [], + activity: [], + }; + + const simulation = network.simulation; + if (!simulation) return { nodes: [], activity: [] }; + + const { activity } = simulation; + const { lightning } = network.nodes; + + activity.forEach(a => { + const { source, destination, intervalSecs, amountMsat } = a; + const nodeNames = [source, destination]; + + for (const nodeName of nodeNames) { + let simNode: SimulationNodeConfig; + + const node = lightning.find(n => n.name === nodeName); + if (!node) { + throw new Error(`Node ${nodeName} not found in network`); + } + + // Split the macaroon and cert path at "volumes/" to get the relative path + // to the docker volume. This is necessary because the docker volumes are + // mounted as a different path in the container. + switch (node.implementation) { + case 'LND': + const lnd = node as LndNode; + simNode = { + id: lnd.name, + macaroon: `/home/simln/.${lnd.paths.adminMacaroon.split('volumes/').pop()}`, + address: `https://host.docker.internal:${lnd.ports.grpc}`, + cert: `/home/simln/.${lnd.paths.tlsCert.split('volumes/').pop()}`, + }; + break; + + default: + throw new Error(`unsupported node implementation: ${node.implementation}`); + } + + // Add the node to the nodes Set. + simJson.nodes.push(simNode); + } + + // Add the activity + const activity: ActivityConfig = { + source: source, + destination: destination, + interval_secs: intervalSecs, + amount_msat: amountMsat, + }; + + // Add the activity to the activity Set. + simJson.activity.push(activity); + }); + + // Remove duplicate nodes. + const uniqueNodes = [...new Map(simJson.nodes.map(node => [node.id, node])).values()]; + + return { + nodes: uniqueNodes, + activity: simJson.activity, + }; + } + + /** + * Start a simulation in the network using docker compose + * @param network the network containing the simulation + */ + async startSimulation(network: Network) { + const simJson = this.constructSimJson(network); + await this.ensureDirs(network, [ + ...network.nodes.bitcoin, + ...network.nodes.lightning, + ...network.nodes.tap, + ]); + const simjsonPath = nodePath(network, 'simln', 'sim.json'); + await write(simjsonPath, JSON.stringify(simJson)); + const result = await this.execute(compose.upOne, 'simln', this.getArgs(network)); + info(`Simulation started:\n ${result.out || result.err}`); + } + + async stopSimulation(network: Network) { + info(`Stopping simulation for ${network.name}`); + const result = await this.execute(compose.stopOne, 'simln', this.getArgs(network)); + info(`Simulation stopped:\n ${result.out || result.err}`); + } + + async removeSimulation(network: Network) { + info(`Stopping docker container for simulation`); + let result = await this.execute(compose.stopOne, 'simln', this.getArgs(network)); + info(`Simulation stopped:\n ${result.out || result.err}`); + + info(`Removing stopped docker containers`); + result = await this.execute(compose.rm as any, this.getArgs(network), 'simln'); + info(`Simulation removed:\n ${result.out || result.err}`); + } } export default new DockerService(); diff --git a/src/lib/docker/nodeTemplates.ts b/src/lib/docker/nodeTemplates.ts index ccd9a39579..d2161c019b 100644 --- a/src/lib/docker/nodeTemplates.ts +++ b/src/lib/docker/nodeTemplates.ts @@ -181,3 +181,24 @@ export const litd = ( `${webPort}:8443`, // web ], }); + +export const simln = ( + name: string, + container: string, + image: string, + command: string, + environment: Record, +): ComposeService => ({ + image, + container_name: container, + hostname: name, + command: trimInside(command), + environment, + restart: 'always', + volumes: [ + `./volumes/${name}:/home/simln/.simln`, + `./volumes/${dockerConfigs.LND.volumeDirName}:/home/simln/.lnd`, + ], + expose: [], + ports: [], +}); diff --git a/src/shared/types.ts b/src/shared/types.ts index 2b3d948781..e594f57f98 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -132,6 +132,8 @@ export type NodeImplementation = | LightningNode['implementation'] | TapNode['implementation']; +export type NodeImplementationWithSimln = NodeImplementation | 'simln'; + export type AnyNode = BitcoinNode | LightningNode | TapNode; export type TapSupportedNode = TapdNode | LitdNode; diff --git a/src/types/index.ts b/src/types/index.ts index 79402b7675..87461c6dc7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -32,6 +32,7 @@ export interface Network { tap: TapNode[]; }; manualMineCount: number; + simulation?: Simulation; } /** @@ -101,6 +102,7 @@ export interface DockerConfig { variables: string[]; dataDir?: string; apiDir?: string; + env?: Record; } export interface DockerRepoImage { @@ -137,6 +139,9 @@ export interface DockerLibrary { saveNetworks: (networks: NetworksFile) => Promise; loadNetworks: () => Promise; renameNodeDir: (network: Network, node: AnyNode, newName: string) => Promise; + startSimulation: (network: Network) => Promise; + stopSimulation: (network: Network) => Promise; + removeSimulation: (network: Network) => Promise; } export interface RepoServiceInjection { @@ -299,3 +304,31 @@ export interface PreInvoice { channelId: string; nextLocalBalance: number; } + +export interface Activity { + id: number; + source: string; + destination: string; + intervalSecs: number; + amountMsat: number; +} + +export interface Simulation { + activity: Activity[]; + status: Status; + errorMsg?: string; +} + +export interface ActivityConfig { + source: string; + destination: string; + interval_secs: number; + amount_msat: number; +} + +export interface SimulationNodeConfig { + id: string; + address: string; + macaroon: string; + cert?: string; +} diff --git a/src/utils/config.ts b/src/utils/config.ts index cdadf02810..84744f1935 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,6 +1,6 @@ import { remote } from 'electron'; import { join } from 'path'; -import { NodeImplementation } from 'shared/types'; +import { NodeImplementationWithSimln } from 'shared/types'; import { Network } from 'types'; import { dockerConfigs } from './constants'; import { existsSync } from 'fs'; @@ -32,7 +32,7 @@ export const networksPath = join(dataPath, 'networks'); */ export const nodePath = ( network: Network, - implementation: NodeImplementation, + implementation: NodeImplementationWithSimln, name: string, ): string => join(network.path, 'volumes', dockerConfigs[implementation].volumeDirName, name); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index ad412b5a23..003d021637 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,4 +1,4 @@ -import { NodeImplementation } from 'shared/types'; +import { NodeImplementation, NodeImplementationWithSimln } from 'shared/types'; import { DockerConfig, DockerRepoState } from 'types'; import bitcoindLogo from 'resources/bitcoin.svg'; import clightningLogo from 'resources/clightning.png'; @@ -97,7 +97,7 @@ export const litdCredentials = { pass: 'polarpass', }; -export const dockerConfigs: Record = { +export const dockerConfigs: Record = { LND: { name: 'LND', imageName: 'polarlightning/lnd', @@ -125,6 +125,8 @@ export const dockerConfigs: Record = { '--bitcoind.rpcpass={{rpcPass}}', '--bitcoind.zmqpubrawblock=tcp://{{backendName}}:28334', '--bitcoind.zmqpubrawtx=tcp://{{backendName}}:28335', + '--accept-keysend', + '--accept-amp', ].join('\n '), // if vars are modified, also update composeFile.ts & the i18n strings for cmps.nodes.CommandVariables variables: ['name', 'containerName', 'backendName', 'rpcUser', 'rpcPass'], @@ -326,6 +328,20 @@ export const dockerConfigs: Record = { 'proofCourier', ], }, + simln: { + name: 'simln', + imageName: 'polarlightning/simln:0.2.5', + logo: '', + platforms: ['mac', 'linux', 'windows'], + volumeDirName: 'simln', + env: { + SIMFILE_PATH: '/home/simln/.simln/sim.json', + DATA_DIR: '/home/simln/.simln', + LOG_LEVEL: 'info', + }, + command: '', + variables: [], + }, }; /** diff --git a/src/utils/network.ts b/src/utils/network.ts index 5f826c7b5f..dbace46ce4 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -30,6 +30,7 @@ import { Network, NetworksFile, NodeBasePorts, + Simulation, } from 'types'; import { dataPath, networksPath, nodePath } from './config'; import { BasePorts, DOCKER_REPO, dockerConfigs } from './constants'; @@ -457,6 +458,7 @@ export const createNetwork = (config: { status?: Status; basePorts?: NodeBasePorts; manualMineCount: number; + simulation?: Simulation; }): Network => { const { id, @@ -473,6 +475,7 @@ export const createNetwork = (config: { customImages, basePorts, manualMineCount, + simulation, } = config; // need explicit undefined check because Status.Starting is 0 const status = config.status !== undefined ? config.status : Status.Stopped; @@ -490,6 +493,7 @@ export const createNetwork = (config: { }, autoMineMode: AutoMineMode.AutoOff, manualMineCount, + simulation, }; const { bitcoin, lightning } = network.nodes; diff --git a/src/utils/tests/renderWithProviders.tsx b/src/utils/tests/renderWithProviders.tsx index ac57e83f08..c80d092d31 100644 --- a/src/utils/tests/renderWithProviders.tsx +++ b/src/utils/tests/renderWithProviders.tsx @@ -69,6 +69,9 @@ export const injections: StoreInjections = { saveNetworks: jest.fn(), loadNetworks: jest.fn(), renameNodeDir: jest.fn(), + startSimulation: jest.fn(), + stopSimulation: jest.fn(), + removeSimulation: jest.fn(), }, repoService: { load: jest.fn(), From 35c870b57da436f2058b96c3bea937d5d3c5e9c1 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Wed, 5 Mar 2025 09:44:52 +0100 Subject: [PATCH 58/77] feat: update network model --- src/i18n/locales/en-US.json | 2 + src/store/models/network.ts | 179 +++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 3 deletions(-) diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index b4b6f02161..53899756c8 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -611,12 +611,14 @@ "store.models.network.nodeByNameErr": "The node '{{name}}' was not found.", "store.models.network.connectedErr": "The node '{{lnName}}' is already connected to '{{backendName}}'", "store.models.network.removeTapdErr": "Cannot remove a Lightning node that has a Taproot Assets node connected to it.", + "store.models.network.removeSimulationErr": "Cannot remove {{lnName}} because it is connected to a simulation.", "store.models.network.removeLastErr": "Cannot remove the only bitcoin node", "store.models.network.removeCompatErr": "There are no other compatible backends for {{lnName}} to connect to. You must remove the {{lnName}} node first", "store.models.network.exportTitle": "Export '{{name}}'", "store.models.network.exportBadStatus": "The network must be stopped to be exported", "store.models.network.missingImages": "Cannot start the network because it contains custom node images that are not available on this machine", "store.models.network.missingNetworkName": "Network must have a name", + "store.models.network.nodeNotStarted": "The {{nodeName}} node is not started", "utils.network.backendCompatError": "This network does not contain a Bitcoin Core v{{requiredVersion}} (or lower) node which is required for {{implementation}} v{{version}}", "utils.network.lndBackendCompatError": "This network does not contain a LND v{{requiredVersion}} (or higher) node which is required for {{implementation}} v{{version}}", "utils.network.incompatibleImplementation": "Importing networks with {{implementation}} nodes is not supported on {{platform}}", diff --git a/src/store/models/network.ts b/src/store/models/network.ts index 7d7923b811..a28fef4842 100644 --- a/src/store/models/network.ts +++ b/src/store/models/network.ts @@ -14,7 +14,7 @@ import { TapdNode, TapNode, } from 'shared/types'; -import { AutoMineMode, CustomImage, Network, StoreInjections } from 'types'; +import { AutoMineMode, CustomImage, Network, StoreInjections, Simulation } from 'types'; import { delay } from 'utils/async'; import { initChartFromNetwork } from 'utils/chart'; import { APP_VERSION, DOCKER_REPO } from 'utils/constants'; @@ -129,7 +129,14 @@ export interface NetworkModel { >; setStatus: Action< NetworkModel, - { id: number; status: Status; only?: string; all?: boolean; error?: Error } + { + id: number; + status: Status; + only?: string; + all?: boolean; + error?: Error; + sim?: boolean; + } >; start: Thunk>; stop: Thunk>; @@ -201,6 +208,34 @@ export interface NetworkModel { RootModel, Promise >; + startSimulation: Thunk< + NetworkModel, + { id: number }, + StoreInjections, + RootModel, + Promise + >; + stopSimulation: Thunk< + NetworkModel, + { id: number }, + StoreInjections, + RootModel, + Promise + >; + addSimulation: Thunk< + NetworkModel, + { simulation: Simulation; networkId: number }, + StoreInjections, + RootModel, + Promise + >; + removeSimulation: Thunk< + NetworkModel, + { id: number; networkId: number }, + StoreInjections, + RootModel, + Promise + >; } const networkModel: NetworkModel = { @@ -450,6 +485,18 @@ const networkModel: NetworkModel = { throw new Error(l('removeTapdErr', { lnName: node.name })); } } + + // Don't allow removing a lightning node if it has a simulation. + if (network.simulation) { + const { activity } = network.simulation; + const activityNode = activity.find( + a => a.source === node.name || a.destination === node.name, + ); + if (activityNode) { + throw new Error(l('removeSimulationErr', { lnName: node.name })); + } + } + // remove the node from the network network.nodes.lightning = network.nodes.lightning.filter(n => n !== node); // remove the node's data from the lightning redux state @@ -652,13 +699,21 @@ const networkModel: NetworkModel = { getStoreActions().designer.updateTapBackendLink({ tapName, lndName: lndName }); }, ), - setStatus: action((state, { id, status, only, all = true, error }) => { + setStatus: action((state, { id, status, only, all = true, error, sim = false }) => { const network = state.networks.find(n => n.id === id); if (!network) throw new Error(l('networkByIdErr', { networkId: id })); + + if (sim && network.simulation) { + network.simulation.status = status; + network.simulation.errorMsg = error && error.message; + return; + } + const setNodeStatus = (n: CommonNode) => { n.status = status; n.errorMsg = error && error.message; }; + if (only) { // only update a specific node's status network.nodes.lightning.filter(n => n.name === only).forEach(setNodeStatus); @@ -729,6 +784,9 @@ const networkModel: NetworkModel = { actions.autoMine({ id: network.id, mode: AutoMineMode.AutoOff }); actions.setStatus({ id: network.id, status: Status.Stopping }); try { + if (network.simulation) { + await actions.removeSimulation({ id: -1, networkId: network.id }); + } await injections.dockerService.stop(network); actions.setStatus({ id: network.id, status: Status.Stopped }); // Remove listeners from lightning nodes @@ -1097,6 +1155,121 @@ const networkModel: NetworkModel = { actions.setManualMineCount({ id, count }); await actions.save(); }), + addSimulation: thunk( + async (actions, { simulation, networkId }, { getState, injections }) => { + const networks = getState().networks; + const network = networks.find(n => n.id === networkId); + if (!network) throw new Error(l('networkByIdErr', { networkId })); + + // add new simulation to the network, but if it already exists, update it + // by adding the new activity to the existing simulation. + if (network.simulation) { + network.simulation.activity = [ + ...network.simulation.activity, + ...simulation.activity, + ]; + } else { + network.simulation = simulation; + } + + actions.setNetworks([...networks]); + await actions.save(); + await injections.dockerService.saveComposeFile(network); + info(`Added new simulation to the network`, simulation); + }, + ), + removeSimulation: thunk( + async (actions, { id, networkId }, { getState, injections }) => { + const networks = getState().networks; + const network = networks.find(n => n.id === networkId); + if (!network) { + throw new Error(l('networkByIdErr', { networkId })); + } + + if (!network.simulation) throw new Error('No simulation found'); + + switch (id) { + case -1: + if (network.simulation?.status !== Status.Stopped) { + actions.setStatus({ + id: networkId, + status: Status.Stopping, + sim: true, + all: false, + }); + } + await injections.dockerService.removeSimulation(network); + // remove the activity from the network. + network.simulation = undefined; + break; + default: + const activity = network.simulation.activity.filter(a => a.id !== id); + network.simulation.activity = activity; + break; + } + + actions.setNetworks([...networks]); + await actions.save(); + await injections.dockerService.saveComposeFile(network); + info(`Removed simulation '${id}' from redux state`, network.simulation); + }, + ), + startSimulation: thunk(async (actions, { id }, { getState, injections }) => { + const network = getState().networks.find(n => n.id === id); + if (!network) throw new Error(l('networkByIdErr', { networkId: id })); + + const simulation = network.simulation; + if (!simulation) { + throw new Error('No simulation found'); + } + const { activity } = simulation; + + await actions.save(); + await injections.dockerService.saveComposeFile(network); + actions.setStatus({ id, status: Status.Starting, sim: true, all: false }); + try { + const lightningNodes = network.nodes.lightning; + + for (const a of activity) { + const { source, destination } = a; + const sourceNode = lightningNodes.find(node => node.name === source); + const destinationNode = lightningNodes.find(node => node.name === destination); + if (!sourceNode || !destinationNode) { + throw new Error('Source or destination node not found'); + } + + if (sourceNode.status != Status.Started) + throw new Error(l('nodeNotStarted', { nodeName: source })); + if (destinationNode.status != Status.Started) + throw new Error(l('nodeNotStarted', { nodeName: destination })); + } + + await injections.dockerService.saveComposeFile(network); + await injections.dockerService.startSimulation(network); + actions.setStatus({ id, status: Status.Started, sim: true, all: false }); + info(`Simulation started for network '${network.name}'`); + } catch (e: any) { + info(`unable to start simulation for network '${network.name}'`, e.message); + actions.setStatus({ id, status: Status.Error, sim: true, error: e, all: false }); + throw e; + } + }), + stopSimulation: thunk(async (actions, { id }, { getState, injections }) => { + const network = getState().networks.find(n => n.id === id); + if (!network) { + throw new Error(l('networkByIdErr', { networkId: id })); + } + actions.setStatus({ id, status: Status.Stopping, sim: true, all: false }); + try { + await injections.dockerService.stopSimulation(network); + info(`Simulation stopped for network '${network.name}'`); + actions.setStatus({ id, status: Status.Stopped, sim: true, all: false }); + } catch (e: any) { + info(`unable to stop simulation for network '${network.name}'`, e.message); + actions.setStatus({ id, status: Status.Error, sim: true, error: e, all: false }); + throw e; + } + }), }; export default networkModel; From c0ad42780b5a04ea8fad50561d33f7697d1ace59 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Tue, 5 Aug 2025 00:16:45 +0100 Subject: [PATCH 59/77] refactor: extract status button In this commit we extract status button logic into a component so that we can reuse it in other places. --- src/components/common/StatusButton.spec.tsx | 34 ++++++++++ src/components/common/StatusButton.tsx | 75 +++++++++++++++++++++ src/components/network/NetworkActions.tsx | 59 +--------------- src/components/network/NetworkView.spec.tsx | 20 ++---- 4 files changed, 116 insertions(+), 72 deletions(-) create mode 100644 src/components/common/StatusButton.spec.tsx create mode 100644 src/components/common/StatusButton.tsx diff --git a/src/components/common/StatusButton.spec.tsx b/src/components/common/StatusButton.spec.tsx new file mode 100644 index 0000000000..5ecc3a092e --- /dev/null +++ b/src/components/common/StatusButton.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { Status } from 'shared/types'; +import { renderWithProviders } from 'utils/tests'; +import StatusButton from './StatusButton'; + +describe('StatusButton Component', () => { + const renderComponent = (status: Status) => + renderWithProviders( ''} />); + + it('should render starting button', () => { + const { getByText } = renderComponent(Status.Starting); + expect(getByText('Starting')).toBeInTheDocument(); + }); + + it('should render started button', () => { + const { getByText } = renderComponent(Status.Started); + expect(getByText('Stop')).toBeInTheDocument(); + }); + + it('should render stopping button', () => { + const { getByText } = renderComponent(Status.Stopping); + expect(getByText('Stopping')).toBeInTheDocument(); + }); + + it('should render stopped button', () => { + const { getByText } = renderComponent(Status.Stopped); + expect(getByText('Start')).toBeInTheDocument(); + }); + + it('should render error button', () => { + const { getByText } = renderComponent(Status.Error); + expect(getByText('Restart')).toBeInTheDocument(); + }); +}); diff --git a/src/components/common/StatusButton.tsx b/src/components/common/StatusButton.tsx new file mode 100644 index 0000000000..ccbba2b17a --- /dev/null +++ b/src/components/common/StatusButton.tsx @@ -0,0 +1,75 @@ +import React, { ReactNode } from 'react'; +import styled from '@emotion/styled'; +import { Button } from 'antd'; +import { Status } from 'shared/types'; +import { ButtonType } from 'antd/lib/button'; +import { PlayCircleOutlined, StopOutlined, WarningOutlined } from '@ant-design/icons'; + +const Styled = { + Button: styled(Button)` + margin-left: 0; + `, +}; + +interface StatusButtonProps { + status: Status; + onClick: () => void; +} + +const config: { + [key: number]: { + label: string; + type: ButtonType; + danger?: boolean; + icon: ReactNode; + }; +} = { + [Status.Starting]: { + label: 'Starting', + type: 'primary', + icon: '', + }, + [Status.Started]: { + label: 'Stop', + type: 'primary', + danger: true, + icon: , + }, + [Status.Stopping]: { + label: 'Stopping', + type: 'default', + icon: '', + }, + [Status.Stopped]: { + label: 'Start', + type: 'primary', + icon: , + }, + [Status.Error]: { + label: 'Restart', + type: 'primary', + danger: true, + icon: , + }, +}; + +const StatusButton: React.FC = ({ status, onClick }) => { + const { type, danger, icon, label } = config[status]; + const ghost = status === Status.Started; + const loading = status === Status.Starting || status === Status.Stopping; + return ( + + {label} + + ); +}; + +export default StatusButton; diff --git a/src/components/network/NetworkActions.tsx b/src/components/network/NetworkActions.tsx index 50ab3b5613..12410f7b63 100644 --- a/src/components/network/NetworkActions.tsx +++ b/src/components/network/NetworkActions.tsx @@ -1,17 +1,13 @@ -import React, { ReactNode, useCallback } from 'react'; +import React, { useCallback } from 'react'; import { CloseOutlined, ExportOutlined, FormOutlined, MoreOutlined, - PlayCircleOutlined, - StopOutlined, ToolOutlined, - WarningOutlined, } from '@ant-design/icons'; import styled from '@emotion/styled'; import { Button, Divider, Dropdown, MenuProps, Tag } from 'antd'; -import { ButtonType } from 'antd/lib/button'; import { usePrefixedTranslation } from 'hooks'; import { useMiningAsync } from 'hooks/useMiningAsync'; import { Status } from 'shared/types'; @@ -21,6 +17,7 @@ import { getNetworkBackendId } from 'utils/network'; import BalanceChannelsButton from 'components/common/BalanceChannelsButton'; import AutoMineButton from 'components/designer/AutoMineButton'; import SyncButton from 'components/designer/SyncButton'; +import StatusButton from 'components/common/StatusButton'; const Styled = { Button: styled(Button)` @@ -39,43 +36,6 @@ interface Props { onExportClick: () => void; } -const config: { - [key: number]: { - label: string; - type: ButtonType; - danger?: boolean; - icon: ReactNode; - }; -} = { - [Status.Starting]: { - label: 'Starting', - type: 'primary', - icon: '', - }, - [Status.Started]: { - label: 'Stop', - type: 'primary', - danger: true, - icon: , - }, - [Status.Stopping]: { - label: 'Stopping', - type: 'default', - icon: '', - }, - [Status.Stopped]: { - label: 'Start', - type: 'primary', - icon: , - }, - [Status.Error]: { - label: 'Restart', - type: 'primary', - danger: true, - icon: , - }, -}; - const NetworkActions: React.FC = ({ network, onClick, @@ -87,9 +47,6 @@ const NetworkActions: React.FC = ({ const { status, nodes } = network; const bitcoinNode = nodes.bitcoin[0]; - const loading = status === Status.Starting || status === Status.Stopping; - const started = status === Status.Started; - const { label, type, danger, icon } = config[status]; const nodeState = useStoreState(s => s.bitcoin.nodes[getNetworkBackendId(bitcoinNode)]); @@ -133,17 +90,7 @@ const NetworkActions: React.FC = ({ )} - - {l(`primaryBtn${label}`)} - + { expect(await findByText(errorMsg)).toBeInTheDocument(); }); - it('should change UI when network is started', async () => { + it('should show Start button when network is stopped', async () => { const { getByText } = renderComponent('1'); const primaryBtn = getByText('Start'); - fireEvent.click(primaryBtn); - // should switch to stopping immediately - expect(primaryBtn).toHaveTextContent('Starting'); - // should change to stopped after some time - await waitFor(() => { - expect(primaryBtn).toHaveTextContent('Stop'); - }); + expect(primaryBtn).toBeInTheDocument(); }); - it('should change UI when network is stopped', async () => { + it('should show Stop button when network is started', async () => { const { getByText } = renderComponent('1', Status.Started); const primaryBtn = getByText('Stop'); - fireEvent.click(primaryBtn); - // should switch to stopping immediately - expect(primaryBtn).toHaveTextContent('Stopping'); - // should change to stopped after some time - await waitFor(() => { - expect(primaryBtn).toHaveTextContent('Start'); - }); + expect(primaryBtn).toBeInTheDocument(); }); it('should do nothing when network is starting', async () => { From 73bcb436fac87a91e6c61e20eea5679458685b55 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Thu, 6 Mar 2025 22:31:13 +0100 Subject: [PATCH 60/77] feat: add simulation management --- src/components/common/StatusButton.tsx | 7 +- src/components/designer/Sidebar.tsx | 2 +- .../designer/default/AddSimulationModal.tsx | 51 ++++- .../designer/default/DefaultSidebar.spec.tsx | 2 +- .../designer/default/DefaultSidebar.tsx | 9 +- .../default/SimulationDesignerTab.tsx | 213 ++++++++++++++++-- src/i18n/locales/en-US.json | 17 ++ 7 files changed, 277 insertions(+), 24 deletions(-) diff --git a/src/components/common/StatusButton.tsx b/src/components/common/StatusButton.tsx index ccbba2b17a..0d73dc04a6 100644 --- a/src/components/common/StatusButton.tsx +++ b/src/components/common/StatusButton.tsx @@ -6,14 +6,16 @@ import { ButtonType } from 'antd/lib/button'; import { PlayCircleOutlined, StopOutlined, WarningOutlined } from '@ant-design/icons'; const Styled = { - Button: styled(Button)` + Button: styled(Button)<{ fullWidth?: boolean }>` margin-left: 0; + ${({ fullWidth }) => fullWidth && 'width: 100%;'} `, }; interface StatusButtonProps { status: Status; onClick: () => void; + fullWidth?: boolean; } const config: { @@ -53,7 +55,7 @@ const config: { }, }; -const StatusButton: React.FC = ({ status, onClick }) => { +const StatusButton: React.FC = ({ status, onClick, fullWidth }) => { const { type, danger, icon, label } = config[status]; const ghost = status === Status.Started; const loading = status === Status.Starting || status === Status.Stopping; @@ -66,6 +68,7 @@ const StatusButton: React.FC = ({ status, onClick }) => { loading={loading} ghost={ghost} onClick={onClick} + fullWidth={fullWidth} > {label} diff --git a/src/components/designer/Sidebar.tsx b/src/components/designer/Sidebar.tsx index a5e4ec88bb..0332cf6770 100644 --- a/src/components/designer/Sidebar.tsx +++ b/src/components/designer/Sidebar.tsx @@ -32,7 +32,7 @@ const Sidebar: React.FC = ({ network, chart }) => { return link && ; } - return ; + return ; }, [network, chart.selected, chart.links]); return <>{cmp}; diff --git a/src/components/designer/default/AddSimulationModal.tsx b/src/components/designer/default/AddSimulationModal.tsx index 7047131a11..21f74693dd 100644 --- a/src/components/designer/default/AddSimulationModal.tsx +++ b/src/components/designer/default/AddSimulationModal.tsx @@ -5,8 +5,9 @@ import { useStoreState } from 'store'; import { usePrefixedTranslation } from 'hooks'; import LightningNodeSelect from 'components/common/form/LightningNodeSelect'; import { Status } from 'shared/types'; -import { Network } from 'types'; import styled from '@emotion/styled'; +import { Activity, Network } from 'types'; +import { useAsyncCallback } from 'react-async-hook'; interface Props { network: Network; @@ -20,6 +21,12 @@ const Styled = { width: 100%; `, }; +interface FormValues { + source: string; + destination: string; + intervalSecs: number; + amountSat: number; +} const AddSimulationModal: React.FC = ({ network }) => { const { l } = usePrefixedTranslation('cmps.designer.default.AddSimulationModal'); @@ -29,11 +36,47 @@ const AddSimulationModal: React.FC = ({ network }) => { const [form] = Form.useForm(); const { visible } = useStoreState(s => s.modals.addSimulation); const { hideAddSimulation } = useStoreActions(s => s.modals); + const { addSimulation } = useStoreActions(s => s.network); + + const { notify } = useStoreActions(s => s.app); const selectedSource = Form.useWatch('source', form) || ''; const selectedDestination = Form.useWatch('destination', form) || ''; const isSameNode = selectedSource === selectedDestination; + const addSimulationAsync = useAsyncCallback(async (values: FormValues) => { + const { lightning } = network.nodes; + const source = lightning.find(n => n.name === values.source); + const destination = lightning.find(n => n.name === values.destination); + + if (!source || !destination) { + notify({ message: l('sourceOrDestinationNotFound') }); + return; + } + + const { intervalSecs, amountSat } = values; + const id = network.simulation?.activity.length + ? Math.max(...network.simulation.activity.map(a => a.id)) + 1 + : 0; + const activity: Activity = { + id, + source: source.name, + destination: destination.name, + intervalSecs, + amountMsat: amountSat * 1000, + }; + + await addSimulation({ + networkId: network.id, + simulation: { + activity: [activity], + status: Status.Stopped, + }, + }); + + hideAddSimulation(); + }); + return ( = ({ network }) => { okText={l('createBtn')} okButtonProps={{ disabled: isSameNode, + loading: addSimulationAsync.loading, }} + onOk={form.submit} >
= ({ network }) => { amountSat: 1000, intervalSecs: 10, }} + onFinish={addSimulationAsync.execute} + disabled={addSimulationAsync.loading} > {isSameNode && } @@ -97,7 +144,7 @@ const AddSimulationModal: React.FC = ({ network }) => { diff --git a/src/components/designer/default/DefaultSidebar.spec.tsx b/src/components/designer/default/DefaultSidebar.spec.tsx index 9bb114640b..589f2c9eba 100644 --- a/src/components/designer/default/DefaultSidebar.spec.tsx +++ b/src/components/designer/default/DefaultSidebar.spec.tsx @@ -58,7 +58,7 @@ describe('DefaultSidebar Component', () => { }, }; - const result = renderWithProviders(, { + const result = renderWithProviders(, { initialState, }); return { diff --git a/src/components/designer/default/DefaultSidebar.tsx b/src/components/designer/default/DefaultSidebar.tsx index c432667dc8..19f699f2cf 100644 --- a/src/components/designer/default/DefaultSidebar.tsx +++ b/src/components/designer/default/DefaultSidebar.tsx @@ -3,8 +3,13 @@ import { usePrefixedTranslation } from 'hooks'; import SidebarCard from '../SidebarCard'; import NetworkDesignerTab from './NetworkDesignerTab'; import SimulationDesignerTab from './SimulationDesignerTab'; +import { Network } from 'types'; -const DefaultSidebar: React.FC = () => { +interface Props { + network: Network; +} + +const DefaultSidebar: React.FC = ({ network }) => { const { l } = usePrefixedTranslation('cmps.designer.default.DefaultSidebar'); const [activeTab, setActiveTab] = useState('network'); @@ -14,7 +19,7 @@ const DefaultSidebar: React.FC = () => { ]; const tabContents: Record = { network: , - simulation: , + simulation: , }; return ( diff --git a/src/components/designer/default/SimulationDesignerTab.tsx b/src/components/designer/default/SimulationDesignerTab.tsx index 1f064e63b2..1f0ace72f4 100644 --- a/src/components/designer/default/SimulationDesignerTab.tsx +++ b/src/components/designer/default/SimulationDesignerTab.tsx @@ -1,10 +1,22 @@ -import React from 'react'; +import React, { ReactNode, useCallback, useEffect } from 'react'; import styled from '@emotion/styled'; import { usePrefixedTranslation } from 'hooks'; -import { Button, Empty } from 'antd'; -import { Tooltip } from 'antd'; -import { PlusOutlined } from '@ant-design/icons'; -import { useStoreActions } from 'store'; +import { Button, Empty, Modal, Tooltip, MenuProps, Dropdown, Alert } from 'antd'; +import { + ArrowRightOutlined, + PlusOutlined, + CloseOutlined, + MoreOutlined, +} from '@ant-design/icons'; +import { useStoreActions, useStoreState } from 'store'; +import { Network } from 'types'; +import { useAsyncCallback } from 'react-async-hook'; +import { Status } from 'shared/types'; +import StatusButton from 'components/common/StatusButton'; + +interface Props { + network: Network; +} const Styled = { Title: styled.div` @@ -14,13 +26,189 @@ const Styled = { margin-bottom: 10px; font-weight: bold; `, + SimContainer: styled.div` + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + height: 46px; + padding: 10px 15px; + margin-top: 20px; + margin-bottom: 20px; + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 4px; + font-weight: bold; + `, + NodeWrapper: styled.div` + display: flex; + align-items: center; + justify-content: start; + column-gap: 15px; + width: 100%; + `, + Dropdown: styled(Dropdown)` + margin-left: 12px; + `, + ViewLogsButton: styled(Button)` + margin-top: 10px; + width: 100%; + `, }; -const SimulationDesignerTab: React.FC = () => { +const SimulationDesignerTab: React.FC = ({ network }) => { const { l } = usePrefixedTranslation('cmps.designer.default.SimulationDesignerTab'); + // Getting the network from the store makes this component to + // re-render when the network is updated (i.e when we add a simulation). + const { networks } = useStoreState(s => s.network); + const currentNetwork = networks.find(n => n.id === network.id); + const { showAddSimulation } = useStoreActions(s => s.modals); + const { notify, openWindow } = useStoreActions(s => s.app); + + const { startSimulation, stopSimulation, removeSimulation } = useStoreActions( + s => s.network, + ); + + const loading = + currentNetwork?.simulation?.status === Status.Starting || + currentNetwork?.simulation?.status === Status.Stopping; + const started = currentNetwork?.simulation?.status === Status.Started; + const status = currentNetwork?.simulation?.status ?? Status.Stopped; + + const startSimulationAsync = useAsyncCallback(async () => { + if (!network.simulation) return; + if (network.simulation.activity.length === 0) { + notify({ + message: l('noActivities'), + error: new Error('Add activities to the simulation to start it.'), + }); + return; + } + try { + await startSimulation({ id: network.id }); + } catch (error: any) { + notify({ message: l('startError'), error }); + } + }); + + const stopSimulationAsync = useAsyncCallback(async () => { + if (!network.simulation) return; + try { + await stopSimulation({ id: network.id }); + } catch (error: any) { + notify({ message: l('stopError'), error }); + } + }); + + const addSimulation = () => { + showAddSimulation({}); + }; + + let modal: any; + const showRemoveModal = (networkId: number, activityId: number) => { + modal = Modal.confirm({ + title: l('removeTitle'), + content: l('removeDesc'), + okText: l('removeBtn'), + okType: 'danger', + cancelText: l('cancelBtn'), + onOk: async () => { + await removeSimulation({ id: activityId, networkId }); + notify({ message: l('removeSuccess') }); + }, + }); + }; + + const openAsync = useAsyncCallback(async () => { + await openWindow(`/logs/simln/polar-n${network.id}-simln`); + }); + + const handleClick = useCallback( + (activityId: number): MenuProps['onClick'] => + (info: { key: string }) => { + switch (info.key) { + case 'delete': + showRemoveModal(network.id, activityId); + break; + } + }, + [], + ); + + const items: MenuProps['items'] = [ + { + key: 'delete', + label: 'Delete', + icon: , + disabled: started || loading, + }, + ]; + + // cleanup the modal when the component unmounts + useEffect(() => () => modal && modal.destroy(), [modal]); + + let cmp: ReactNode; + + if (network.simulation) { + const { activity } = network.simulation; + cmp = ( + <> + {activity.length === 0 && ( + + )} + {activity.map(a => ( + + + {a.source} + + {a.destination} + + + + + + ))} + + {started && ( + + View Logs + + )} + + ); + } else { + cmp = ( + <> + {network.status !== Status.Started && ( + + )} + + + + + ); + } + return (
@@ -29,19 +217,12 @@ const SimulationDesignerTab: React.FC = () => { - + {cmp}
); }; diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 53899756c8..5460f46bd3 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -121,6 +121,21 @@ "cmps.designer.default.SimulationDesignerTab.createBtn": "Add a new Simulation", "cmps.designer.default.SimulationDesignerTab.title": "Lightning Network Simulation", "cmps.designer.default.SimulationDesignerTab.emptyMsg": "No simulations created yet", + "cmps.designer.default.SimulationDesignerTab.noActivities": "No activities added yet.", + "cmps.designer.default.SimulationDesignerTab.removeTitle": "Remove Simulation", + "cmps.designer.default.SimulationDesignerTab.removeDesc": "Are you sure you want to remove this simulation?", + "cmps.designer.default.SimulationDesignerTab.removeBtn": "Remove", + "cmps.designer.default.SimulationDesignerTab.removeSuccess": "Simulation removed successfully", + "cmps.designer.default.SimulationDesignerTab.removeError": "Failed to remove simulation", + "cmps.designer.default.SimulationDesignerTab.cancelBtn": "Cancel", + "cmps.designer.default.SimulationDesignerTab.primaryBtnStarting": "Starting", + "cmps.designer.default.SimulationDesignerTab.primaryBtnStop": "Stop", + "cmps.designer.default.SimulationDesignerTab.primaryBtnStopping": "Stopping", + "cmps.designer.default.SimulationDesignerTab.primaryBtnStart": "Start", + "cmps.designer.default.SimulationDesignerTab.primaryBtnRestart": "Restart", + "cmps.designer.default.SimulationDesignerTab.startError": "Unable to start the simulation", + "cmps.designer.default.SimulationDesignerTab.stopError": "Unable to stop the simulation", + "cmps.designer.default.SimulationDesignerTab.networkNotStarted": "Network must be started to add simulations", "cmps.designer.default.AddSimulationModal.title": "Add Simulation", "cmps.designer.default.AddSimulationModal.cancelBtn": "Cancel", "cmps.designer.default.AddSimulationModal.createBtn": "Create", @@ -129,6 +144,8 @@ "cmps.designer.default.AddSimulationModal.interval": "Interval (secs)", "cmps.designer.default.AddSimulationModal.amount": "Amount (sat)", "cmps.designer.default.AddSimulationModal.sameNodesWarnMsg": "Cannot create a simulation with the same node for both source and destination", + "cmps.designer.default.AddSimulationModal.sourceOrDestinationNotFound": "Source or destination node not found", + "cmps.designer.default.AddSimulationModal.submitError": "Unable to add the Simulation", "cmps.designer.default.ImageUpdatesModal.title": "Check for new Node Versions", "cmps.designer.default.ImageUpdatesModal.updatesTitle": "There are new node versions available", "cmps.designer.default.ImageUpdatesModal.updatesDesc": "Add the new versions to begin using them in your Lightning networks.", From e56023fbc7446875591a1eed0d489e24ffb4efe5 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Tue, 11 Mar 2025 12:32:47 +0100 Subject: [PATCH 61/77] test: add test to ln simulation --- .../designer/NetworkDesigner.spec.tsx | 9 + .../default/AddSimulationModal.spec.tsx | 155 +++++++++++ .../default/SimulationDesignerTab.spec.tsx | 258 ++++++++++++++++++ src/lib/docker/composeFile.spec.ts | 16 +- src/lib/docker/dockerService.spec.ts | 119 +++++++- src/store/models/network.spec.ts | 231 ++++++++++++++++ 6 files changed, 786 insertions(+), 2 deletions(-) create mode 100644 src/components/designer/default/AddSimulationModal.spec.tsx create mode 100644 src/components/designer/default/SimulationDesignerTab.spec.tsx diff --git a/src/components/designer/NetworkDesigner.spec.tsx b/src/components/designer/NetworkDesigner.spec.tsx index f1169ead88..39404fbc3b 100644 --- a/src/components/designer/NetworkDesigner.spec.tsx +++ b/src/components/designer/NetworkDesigner.spec.tsx @@ -259,6 +259,15 @@ describe('NetworkDesigner Component', () => { fireEvent.click(getByText('Cancel')); }); + it('should display the Add Simulation modal', async () => { + const { getByText, findByText, store } = renderComponent(); + act(() => { + store.getActions().modals.showAddSimulation({}); + }); + expect(await findByText('Add Simulation')).toBeInTheDocument(); + fireEvent.click(getByText('Cancel')); + }); + it('should remove a node from the network', async () => { const { getByText, findByText, queryByText, store } = renderComponent(); // add a new LN node that doesn't have a tap node connected diff --git a/src/components/designer/default/AddSimulationModal.spec.tsx b/src/components/designer/default/AddSimulationModal.spec.tsx new file mode 100644 index 0000000000..b39b2e649a --- /dev/null +++ b/src/components/designer/default/AddSimulationModal.spec.tsx @@ -0,0 +1,155 @@ +import React from 'react'; +import AddSimulationModal from './AddSimulationModal'; +import { createNetwork } from 'utils/network'; +import { defaultRepoState } from 'utils/constants'; +import { renderWithProviders, testManagedImages } from 'utils/tests'; +import { Status } from 'shared/types'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { initChartFromNetwork } from 'utils/chart'; + +describe('AddSimulationModal', () => { + let unmount: () => void; + + const renderComponent = async (status?: Status) => { + const network = createNetwork({ + id: 1, + name: 'test network', + description: 'network description', + lndNodes: 2, + clightningNodes: 0, + eclairNodes: 0, + litdNodes: 0, + bitcoindNodes: 2, + tapdNodes: 0, + repoState: defaultRepoState, + managedImages: testManagedImages, + customImages: [], + status, + manualMineCount: 6, + }); + const chart = initChartFromNetwork(network); + const initialState = { + network: { + networks: [network], + }, + designer: { + activeId: network.id, + allCharts: { + [network.id]: chart, + }, + }, + modals: { + addSimulation: { + visible: true, + }, + }, + }; + + const cmp = ; + const result = renderWithProviders(cmp, { initialState }); + unmount = result.unmount; + return { + ...result, + network, + }; + }; + + afterEach(() => unmount()); + + it('should render labels', async () => { + const { getByText } = await renderComponent(); + expect(getByText('Add Simulation')).toBeInTheDocument(); + expect(getByText('Source')).toBeInTheDocument(); + expect(getByText('Destination')).toBeInTheDocument(); + expect(getByText('Interval (secs)')).toBeInTheDocument(); + expect(getByText('Amount (sat)')).toBeInTheDocument(); + }); + + it('should render form inputs', async () => { + const { getByLabelText } = await renderComponent(); + expect(getByLabelText('Source')).toBeInTheDocument(); + expect(getByLabelText('Destination')).toBeInTheDocument(); + expect(getByLabelText('Interval (secs)')).toBeInTheDocument(); + expect(getByLabelText('Amount (sat)')).toBeInTheDocument(); + }); + + it('should render button', async () => { + const { getByText } = await renderComponent(); + expect(getByText('Create')).toBeInTheDocument(); + }); + + it('should hide modal when cancel is clicked', async () => { + const { getByText, queryByText } = await renderComponent(); + const btn = getByText('Cancel'); + expect(btn).toBeInTheDocument(); + expect(btn.parentElement).toBeInstanceOf(HTMLButtonElement); + fireEvent.click(getByText('Cancel')); + expect(queryByText('Cancel')).not.toBeInTheDocument(); + }); + + it('should do nothing if an invalid node name is used', async () => { + const { getByText } = await renderComponent(); + fireEvent.click(getByText('Create')); + await waitFor(() => { + expect(getByText('Create')).toBeInTheDocument(); + }); + }); + + describe('with form submitted', () => { + it('should create a simulation', async () => { + const { getByText, getByLabelText, store } = await renderComponent(); + fireEvent.change(getByLabelText('Source'), { target: { value: 'alice' } }); + fireEvent.change(getByLabelText('Destination'), { target: { value: 'bob' } }); + fireEvent.change(getByLabelText('Interval (secs)'), { target: { value: '1000' } }); + fireEvent.change(getByLabelText('Amount (sat)'), { target: { value: '1000' } }); + fireEvent.click(getByText('Create')); + await waitFor(() => { + expect(store.getState().modals.addSimulation.visible).toBe(false); + expect(store.getState().network.networks[0].simulation).toBeDefined(); + }); + }); + + it('should add a second activity', async () => { + const { getByText, getByLabelText, store, network } = await renderComponent(); + const activity = { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 1000, + amountMsat: 1000000, + }; + const sim = { + networkId: 1, + status: Status.Stopped, + activity: [activity], + }; + network.simulation = sim; + store.getActions().network.setNetworks([network]); + + fireEvent.change(getByLabelText('Source'), { target: { value: 'bob' } }); + fireEvent.change(getByLabelText('Destination'), { target: { value: 'alice' } }); + fireEvent.change(getByLabelText('Interval (secs)'), { target: { value: '1000' } }); + fireEvent.change(getByLabelText('Amount (sat)'), { target: { value: '1000' } }); + fireEvent.click(getByText('Create')); + await waitFor(() => { + expect(store.getState().modals.addSimulation.visible).toBe(false); + expect(store.getState().network.networks[0].simulation?.activity.length).toBe(2); + }); + }); + + it('should throw an error if source or destination node is not found', async () => { + const { getByText, getByLabelText, network, findByText } = await renderComponent( + Status.Started, + ); + fireEvent.change(getByLabelText('Source'), { target: { value: 'alice' } }); + fireEvent.change(getByLabelText('Destination'), { target: { value: 'bob' } }); + fireEvent.change(getByLabelText('Interval (secs)'), { target: { value: '10' } }); + fireEvent.change(getByLabelText('Amount (sat)'), { target: { value: '1000' } }); + network.nodes.lightning = []; + fireEvent.click(getByText('Create')); + expect( + await findByText('Source or destination node not found'), + ).toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/designer/default/SimulationDesignerTab.spec.tsx b/src/components/designer/default/SimulationDesignerTab.spec.tsx new file mode 100644 index 0000000000..d2b082550f --- /dev/null +++ b/src/components/designer/default/SimulationDesignerTab.spec.tsx @@ -0,0 +1,258 @@ +import React from 'react'; +import { fireEvent, waitFor } from '@testing-library/react'; +import SimulationDesignerTab from './SimulationDesignerTab'; +import { Status } from 'shared/types'; +import { injections, renderWithProviders, testManagedImages } from 'utils/tests'; +import { createNetwork } from 'utils/network'; +import { defaultRepoState } from 'utils/constants'; +import { initChartFromNetwork } from 'utils/chart'; +import { ipcChannels } from 'shared'; + +const mockDockerService = injections.dockerService as jest.Mocked< + typeof injections.dockerService +>; + +describe('SimulationDesignerTab', () => { + const renderComponent = (status?: Status, simStatus?: Status, noSim?: boolean) => { + const network = createNetwork({ + id: 1, + name: 'test network', + description: 'network description', + lndNodes: 2, + clightningNodes: 0, + eclairNodes: 0, + litdNodes: 0, + bitcoindNodes: 2, + tapdNodes: 0, + repoState: defaultRepoState, + managedImages: testManagedImages, + customImages: [], + status, + manualMineCount: 6, + }); + + if (!noSim) { + network.simulation = { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: simStatus ?? Status.Stopped, + }; + } + const chart = initChartFromNetwork(network); + + const initialState = { + network: { + networks: [network], + }, + modals: { + addSimulation: { + visible: false, + }, + }, + designer: { + allCharts: { + [network.id]: chart, + }, + }, + }; + + const result = renderWithProviders(, { + initialState, + }); + + return { + ...result, + network, + }; + }; + + describe('Simulation Designer Tab', () => { + it('should render the simulation designer tab', async () => { + const { getByText, store } = renderComponent(Status.Started, Status.Started, true); + expect(getByText('No simulations created yet')).toBeInTheDocument(); + + const addSimulationBtn = getByText('Add a new Simulation'); + expect(addSimulationBtn).toBeInTheDocument(); + fireEvent.click(addSimulationBtn); + await waitFor(() => { + expect(store.getState().modals.addSimulation.visible).toBe(true); + }); + }); + + it('should show add simulation button if no simulation is defined', async () => { + const { getByText } = renderComponent(Status.Started, Status.Started, true); + expect(getByText('No simulations created yet')).toBeInTheDocument(); + + const addSimulationBtn = getByText('Add a new Simulation'); + expect(addSimulationBtn).toBeInTheDocument(); + }); + }); + + describe('Start Simulation', () => { + it('should start simulation successfully', async () => { + const { getByText } = renderComponent(Status.Started); + expect(getByText('Start')).toBeInTheDocument(); + + fireEvent.click(getByText('Start')); + await waitFor(() => { + expect(mockDockerService.startSimulation).toHaveBeenCalled(); + }); + }); + + it('should show error if simulation fails to start', async () => { + // Simulation should fail to start because the network is not started, + // which means the lightning nodes are not running. + const { getByText } = renderComponent(Status.Stopped); + fireEvent.click(getByText('Start')); + + await waitFor(() => { + expect(getByText('Unable to start the simulation')).toBeInTheDocument(); + }); + }); + }); + + describe('Stop Simulation', () => { + it('should stop simulation successfully', async () => { + const { getByText } = renderComponent(Status.Started, Status.Started); + expect(getByText('Stop')).toBeInTheDocument(); + fireEvent.click(getByText('Stop')); + await waitFor(() => { + expect(mockDockerService.stopSimulation).toHaveBeenCalled(); + }); + }); + + it('should show error if simulation fails to stop', async () => { + mockDockerService.stopSimulation.mockRejectedValue(new Error('simulation-error')); + const { getByText } = renderComponent(Status.Started, Status.Started); + fireEvent.click(getByText('Stop')); + + await waitFor(() => { + expect(getByText('Unable to stop the simulation')).toBeInTheDocument(); + expect(getByText('simulation-error')).toBeInTheDocument(); + }); + }); + }); + + describe('Remove Simulation', () => { + it('should remove simulation', async () => { + const { getByText, getByLabelText, findByText } = renderComponent(Status.Started); + fireEvent.mouseOver(getByLabelText('more')); + fireEvent.click(await findByText('Delete')); + await waitFor(() => { + expect(getByText('Remove Simulation')).toBeInTheDocument(); + }); + + fireEvent.click(getByText('Remove')); + await waitFor(() => { + expect(getByText('Simulation removed successfully')).toBeInTheDocument(); + }); + }); + + it('should return early if no simulation is defined', async () => { + const { getByText, network, findByText, getByLabelText } = renderComponent( + Status.Started, + Status.Stopped, + ); + const activity = { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }; + const sim = { + networkId: 1, + status: Status.Stopped, + activity: [activity], + }; + + // This is an unlikely scenario, as the start button is not + // visible if no simulation is defined. + network.simulation = undefined; + expect(getByText('Start')).toBeInTheDocument(); + fireEvent.click(getByText('Start')); + expect(getByText('No simulations created yet')).toBeInTheDocument(); + + network.simulation = { ...sim, status: Status.Started }; + await waitFor(() => { + expect(getByText('Stop')).toBeInTheDocument(); + }); + network.simulation = undefined; + expect(getByText('Stop')).toBeInTheDocument(); + fireEvent.click(getByText('Stop')); + expect(getByText('No simulations created yet')).toBeInTheDocument(); + + network.simulation = { ...sim, status: Status.Stopped }; + await waitFor(() => { + expect(getByText('Start')).toBeInTheDocument(); + }); + + network.simulation = undefined; + fireEvent.mouseOver(getByLabelText('more')); + fireEvent.click(await findByText('Delete')); + fireEvent.click(await findByText('Remove')); + await waitFor(() => { + expect(mockDockerService.removeSimulation).not.toHaveBeenCalled(); + }); + }); + + it('should show error if no activities are added', async () => { + const { getByText, network, store } = renderComponent( + Status.Started, + Status.Started, + true, + ); + + const sim = { + networkId: 1, + status: Status.Stopped, + activity: [], + }; + + network.simulation = sim; + store.getActions().network.setNetworks([network]); + + fireEvent.click(getByText('Start')); + await waitFor(() => { + expect( + getByText('Add activities to the simulation to start it.'), + ).toBeInTheDocument(); + }); + }); + + it('should send an ipc message when the button is clicked', async () => { + const { getByText, getByLabelText, findByText, network, store } = renderComponent(); + const activity = { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }; + const sim = { + networkId: 1, + status: Status.Started, + activity: [activity], + }; + + network.simulation = sim; + store.getActions().network.setNetworks([network]); + fireEvent.mouseOver(getByLabelText('more')); + fireEvent.click(await findByText('Delete')); + const ipcMock = injections.ipc as jest.Mock; + ipcMock.mockResolvedValue(true); + fireEvent.click(getByText('View Logs')); + const url = '/logs/simln/polar-n1-simln'; + await waitFor(() => { + expect(ipcMock).toBeCalledWith(ipcChannels.openWindow, { url }); + }); + }); + }); +}); diff --git a/src/lib/docker/composeFile.spec.ts b/src/lib/docker/composeFile.spec.ts index c9605ae0e9..c33d0af4d2 100644 --- a/src/lib/docker/composeFile.spec.ts +++ b/src/lib/docker/composeFile.spec.ts @@ -42,7 +42,8 @@ describe('ComposeFile', () => { it('should add multiple services', () => { composeFile.addBitcoind(btcNode); composeFile.addLnd(lndNode, btcNode); - expect(Object.keys(composeFile.content.services).length).toEqual(2); + composeFile.addSimln(1); + expect(Object.keys(composeFile.content.services).length).toEqual(3); }); it('should add a bitcoind config', () => { @@ -191,4 +192,17 @@ describe('ComposeFile', () => { expect(service.image).toBe('my-image'); expect(service.command).toBe('my-command'); }); + + it('should add a simln config', () => { + composeFile.addSimln(1); + expect(composeFile.content.services['simln']).not.toBeUndefined(); + }); + + it('should create the correct simln docker compose values', () => { + composeFile.addSimln(1); + const service = composeFile.content.services['simln']; + expect(service.image).toContain('simln'); + expect(service.container_name).toEqual('polar-n1-simln'); + expect(service.command).toBe(''); + }); }); diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index 44b7e49ff7..ced701cc0c 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -5,7 +5,7 @@ import { IChart } from '@mrblenny/react-flow-chart'; import { v2 as compose } from 'docker-compose'; import Dockerode from 'dockerode'; import os from 'os'; -import { CLightningNode, LitdNode, LndNode, TapdNode } from 'shared/types'; +import { CLightningNode, LitdNode, LndNode, Status, TapdNode } from 'shared/types'; import { dockerService } from 'lib/docker'; import { Network, NetworksFile } from 'types'; import { initChartFromNetwork } from 'utils/chart'; @@ -887,4 +887,121 @@ describe('DockerService', () => { expect(docker1).toBe(docker2); }); }); + + describe('simulation commands', () => { + const network = createNetwork({ + id: 1, + name: 'my network', + description: 'network description', + lndNodes: 2, + clightningNodes: 1, + eclairNodes: 0, + bitcoindNodes: 1, + tapdNodes: 0, + litdNodes: 0, + repoState: defaultRepoState, + managedImages: testManagedImages, + customImages: [], + manualMineCount: 6, + }); + const mockResult = { err: '', out: '', exitCode: 0 }; + const lndNodes = network.nodes.lightning.filter(n => n.implementation === 'LND'); + + beforeEach(() => { + // Add simulation config to the test network + network.simulation = { + activity: [ + { + id: 0, + source: lndNodes[0].name, + destination: lndNodes[1].name, + intervalSecs: 60, + amountMsat: 1000, + }, + ], + status: Status.Stopped, + }; + }); + + it('should start a simulation', async () => { + composeMock.upOne.mockResolvedValue(mockResult); + await dockerService.startSimulation(network); + + // Verify directories were created + expect(fsMock.ensureDir).toHaveBeenCalled(); + + // Verify sim.json was written with correct config + expect(filesMock.write).toHaveBeenCalledWith( + expect.stringContaining('sim.json'), + expect.stringContaining(lndNodes[0].name), + ); + + // Verify docker compose command was called + expect(composeMock.upOne).toHaveBeenCalledWith( + 'simln', + expect.objectContaining({ cwd: network.path }), + ); + }); + + it('should stop a simulation', async () => { + composeMock.stopOne.mockResolvedValue(mockResult); + await dockerService.stopSimulation(network); + + expect(composeMock.stopOne).toHaveBeenCalledWith( + 'simln', + expect.objectContaining({ cwd: network.path }), + ); + }); + + it('should remove a simulation', async () => { + composeMock.stopOne.mockResolvedValue(mockResult); + composeMock.rm.mockResolvedValue(mockResult); + await dockerService.removeSimulation(network); + + // Verify stop was called first + expect(composeMock.stopOne).toHaveBeenCalledWith( + 'simln', + expect.objectContaining({ cwd: network.path }), + ); + + // Verify remove was called after + expect(composeMock.rm).toHaveBeenCalledWith( + expect.objectContaining({ cwd: network.path }), + 'simln', + ); + }); + + it('should handle errors when using unsupported node types', async () => { + network.nodes.lightning[0].implementation = 'c-lightning'; + await expect(dockerService.startSimulation(network)).rejects.toThrow( + 'unsupported node implementation: c-lightning', + ); + }); + + it('should handle errors when node is not found', async () => { + network.simulation!.activity[0].source = 'non-existent'; + await expect(dockerService.startSimulation(network)).rejects.toThrow( + 'Node non-existent not found in network', + ); + }); + + it('should return empty arrays when network has no simulation config', async () => { + // Create network without simulation config + const networkWithoutSim = getNetwork(); + networkWithoutSim.simulation = undefined; + + // Call constructSimJson directly to test the early return + const simJson = dockerService.constructSimJson(networkWithoutSim); + expect(simJson).toEqual({ nodes: [], activity: [] }); + }); + + it('should add simln to the docker-compose.yml file', async () => { + network.simulation = {} as any; + dockerService.saveComposeFile(network); + expect(filesMock.write).toHaveBeenCalledWith( + expect.stringContaining('docker-compose.yml'), + expect.stringContaining(`container_name: polar-n1-simln`), + ); + }); + }); }); diff --git a/src/store/models/network.spec.ts b/src/store/models/network.spec.ts index 3b70fa47c8..b60125d10e 100644 --- a/src/store/models/network.spec.ts +++ b/src/store/models/network.spec.ts @@ -453,6 +453,38 @@ describe('Network model', () => { ); }); + it('should throw if the simulation is connected to a node', async () => { + const { addSimulation, removeLightningNode } = store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: network.id, + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Started, + }, + }; + await addSimulation(config); + await expect( + removeLightningNode({ node: network.nodes.lightning[0] }), + ).rejects.toThrow('Cannot remove alice because it is connected to a simulation.'); + + await expect( + removeLightningNode({ node: network.nodes.lightning[1] }), + ).rejects.toThrow('Cannot remove bob because it is connected to a simulation.'); + + await removeLightningNode({ node: network.nodes.lightning[2] }); + + expect(network.nodes.lightning).toHaveLength(4); + }); + it('should update peers of surrounding bitcoin nodes', async () => { const { removeBitcoinNode, addNode } = store.getActions().network; const { id } = firstNetwork(); @@ -732,6 +764,25 @@ describe('Network model', () => { await stop(firstNetwork().id); expect(lightningServiceMock.removeListener).toHaveBeenCalled(); }); + + it('should remove the simulation when stopping a network', async () => { + const { stop } = store.getActions().network; + const network = firstNetwork(); + network.simulation = { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Stopped, + }; + await stop(firstNetwork().id); + expect(injections.dockerService.removeSimulation).toHaveBeenCalled(); + }); }); describe('Stop all', () => { @@ -1060,6 +1111,186 @@ describe('Network model', () => { }); }); + describe('Simulation', () => { + beforeEach(() => { + const { addNetwork } = store.getActions().network; + addNetwork(addNetworkArgs); + }); + + it('should add simulation', async () => { + const { addSimulation } = store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: 10, // Set to a non-existent network id + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Stopped, + }, + }; + await expect(addSimulation(config)).rejects.toThrow(); + + config.networkId = network.id; // Set to the correct network id + await addSimulation(config); + expect(network.simulation).toEqual(config.simulation); + expect(injections.dockerService.saveComposeFile).toHaveBeenCalled(); + }); + + it('should remove simulation', async () => { + const { removeSimulation, addSimulation } = store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: network.id, + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Started, + }, + }; + await addSimulation(config); + expect(network.simulation).toEqual(config.simulation); + config.networkId = 10; // Set to a non-existent network id + await expect( + removeSimulation({ id: 0, networkId: config.networkId }), + ).rejects.toThrow(); + config.networkId = network.id; // Set to the correct network id + await removeSimulation({ id: 0, networkId: config.networkId }); + expect(network.simulation?.activity.length).toBe(0); + expect(injections.dockerService.saveComposeFile).toHaveBeenCalled(); + }); + + it('should remove simulation when the network is stopped', async () => { + const { addSimulation, stop } = store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: network.id, + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Started, + }, + }; + await addSimulation(config); + expect(network.simulation).toEqual(config.simulation); + + // Stop the network + await stop(network.id); + expect(network.status).toBe(Status.Stopped); + }); + + it('should error if the simulation is not found', async () => { + const { removeSimulation } = store.getActions().network; + const network = firstNetwork(); + await expect(removeSimulation({ id: 0, networkId: network.id })).rejects.toThrow(); + }); + + it('should start and stop simulation', async () => { + const { startSimulation, stopSimulation, addSimulation, start, setStatus } = + store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: network.id, + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Stopped, + }, + }; + await expect(startSimulation({ id: network.id + 10 })).rejects.toThrow(); // Throws if the network id is not valid + // Throws if the simulation is not added to the network yet. + await expect(startSimulation({ id: network.id })).rejects.toThrow(); + + await addSimulation(config); + expect(network.simulation).toEqual(config.simulation); + + // Start the network. + await start(network.id); + + // Set the destination node to stopped. This throws if one of the nodes is not started. + setStatus({ + id: network.id, + status: Status.Stopped, + only: network.nodes.lightning[1].name, + }); + await expect(startSimulation({ id: network.id })).rejects.toThrow(); + + // Set the destination node to started. + setStatus({ id: network.id, status: Status.Started }); + await startSimulation({ id: network.id }); + expect(injections.dockerService.startSimulation).toHaveBeenCalled(); + + // Throws if the network id is not valid. + await expect(stopSimulation({ id: network.id + 10 })).rejects.toThrow(); + + // Stop the simulation. + await stopSimulation({ id: network.id }); + expect(injections.dockerService.stopSimulation).toHaveBeenCalled(); + }); + + it('should fail for non-existent nodes', async () => { + const { startSimulation, addSimulation, start } = store.getActions().network; + const network = firstNetwork(); + const config = { + networkId: network.id, + simulation: { + activity: [ + { + id: 0, + source: network.nodes.lightning[0].name, + destination: network.nodes.lightning[1].name, + intervalSecs: 10, + amountMsat: 1000000, + }, + ], + status: Status.Stopped, + }, + }; + + const nonExistentNode = { + ...network.nodes.lightning[0], + name: 'non-existent', // Set to a non-existent node name + }; + + config.simulation.activity[0].source = nonExistentNode.name; + await addSimulation(config); + await start(network.id); + await expect(startSimulation({ id: network.id })).rejects.toThrow(); + + config.simulation.activity[0].source = network.nodes.lightning[0].name; + config.simulation.activity[0].destination = nonExistentNode.name; + await addSimulation(config); + await expect(startSimulation({ id: network.id })).rejects.toThrow(); + }); + }); + describe('Other actions', () => { it('should remove a network', async () => { expect(store.getState().network.networks).toHaveLength(0); From 955260e9d0350c8ab091580e45217211d7bc1f77 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Wed, 21 May 2025 21:50:05 +0100 Subject: [PATCH 62/77] refactor: extend nodeselector --- src/components/common/form/LightningNodeSelect.spec.tsx | 2 +- src/components/common/form/LightningNodeSelect.tsx | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/common/form/LightningNodeSelect.spec.tsx b/src/components/common/form/LightningNodeSelect.spec.tsx index 3cdee1e4e8..72ead48363 100644 --- a/src/components/common/form/LightningNodeSelect.spec.tsx +++ b/src/components/common/form/LightningNodeSelect.spec.tsx @@ -23,7 +23,7 @@ describe('LightningNodeSelect', () => { name="from" label="Source" initialValue={initialValue} - implementation="LND" + implementation={['LND']} nodes={nodes} /> diff --git a/src/components/common/form/LightningNodeSelect.tsx b/src/components/common/form/LightningNodeSelect.tsx index a038ab9603..9e1e5ff926 100644 --- a/src/components/common/form/LightningNodeSelect.tsx +++ b/src/components/common/form/LightningNodeSelect.tsx @@ -13,7 +13,7 @@ export interface Props extends SelectProps { name: string; label?: string; nodeStatus?: Status; - implementation?: LightningNode['implementation']; + implementation?: LightningNode['implementation'][] | LightningNode['implementation']; initialValue?: string; nodes?: { [key: string]: LightningNodeModel; @@ -54,7 +54,11 @@ const LightningNodeSelect: React.FC = ({ lnNodes = lnNodes.filter(n => n.status === nodeStatus); } if (implementation) { - lnNodes = lnNodes.filter(n => n.implementation === implementation); + if (Array.isArray(implementation)) { + lnNodes = lnNodes.filter(n => implementation.includes(n.implementation)); + } else { + lnNodes = lnNodes.filter(n => n.implementation === implementation); + } } return ( Date: Fri, 23 May 2025 15:56:20 +0100 Subject: [PATCH 63/77] feat: add simln support to eclair --- .../designer/default/AddSimulationModal.tsx | 4 ++-- src/lib/docker/dockerService.spec.ts | 12 +++++++----- src/lib/docker/dockerService.ts | 12 +++++++++++- src/types/index.ts | 10 ++++++++-- src/utils/constants.ts | 1 + 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/components/designer/default/AddSimulationModal.tsx b/src/components/designer/default/AddSimulationModal.tsx index 21f74693dd..b4341f1c52 100644 --- a/src/components/designer/default/AddSimulationModal.tsx +++ b/src/components/designer/default/AddSimulationModal.tsx @@ -113,7 +113,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="source" label={l('source')} nodeStatus={Status.Started} - implementation={'LND'} + implementation={['LND', 'eclair']} nodes={nodes} /> @@ -123,7 +123,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="destination" label={l('destination')} nodeStatus={Status.Started} - implementation={'LND'} + implementation={['LND', 'eclair']} nodes={nodes} /> diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index ced701cc0c..8a7cd8bd14 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -893,9 +893,9 @@ describe('DockerService', () => { id: 1, name: 'my network', description: 'network description', - lndNodes: 2, - clightningNodes: 1, - eclairNodes: 0, + lndNodes: 1, + clightningNodes: 0, + eclairNodes: 1, bitcoindNodes: 1, tapdNodes: 0, litdNodes: 0, @@ -906,7 +906,9 @@ describe('DockerService', () => { }); const mockResult = { err: '', out: '', exitCode: 0 }; const lndNodes = network.nodes.lightning.filter(n => n.implementation === 'LND'); - + const eclairNodes = network.nodes.lightning.filter( + n => n.implementation === 'eclair', + ); beforeEach(() => { // Add simulation config to the test network network.simulation = { @@ -914,7 +916,7 @@ describe('DockerService', () => { { id: 0, source: lndNodes[0].name, - destination: lndNodes[1].name, + destination: eclairNodes[0].name, intervalSecs: 60, amountMsat: 1000, }, diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 047f367595..97fdb152c9 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -27,7 +27,7 @@ import { SimulationNodeConfig, } from 'types'; import { legacyDataPath, networksPath, nodePath } from 'utils/config'; -import { APP_VERSION, dockerConfigs } from 'utils/constants'; +import { APP_VERSION, dockerConfigs, eclairCredentials } from 'utils/constants'; import { exists, read, renameFile, rm, write } from 'utils/files'; import { migrateNetworksFile } from 'utils/migrations'; import { isLinux, isMac } from 'utils/system'; @@ -445,6 +445,16 @@ class DockerService implements DockerLibrary { }; break; + case 'eclair': + const eclair = node as EclairNode; + simNode = { + id: eclair.name, + base_url: `http://host.docker.internal:${eclair.ports.rest}`, + api_username: '', + api_password: eclairCredentials.pass, + }; + break; + default: throw new Error(`unsupported node implementation: ${node.implementation}`); } diff --git a/src/types/index.ts b/src/types/index.ts index 87461c6dc7..af436c53b9 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -328,7 +328,13 @@ export interface ActivityConfig { export interface SimulationNodeConfig { id: string; - address: string; - macaroon: string; + address?: string; + base_url?: string; + macaroon?: string; cert?: string; + ca_cert?: string; + client_cert?: string; + client_key?: string; + api_username?: string; + api_password?: string; } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 003d021637..d8a98b456d 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -192,6 +192,7 @@ export const dockerConfigs: Record = '--on-chain-fees.feerate-tolerance.ratio-high=10000.0', '--channel.max-htlc-value-in-flight-percent=100', '--channel.max-htlc-value-in-flight-msat=5000000000000', // 50 BTC in msats + '--features.keysend=optional', ].join('\n '), // if vars are modified, also update composeFile.ts & the i18n strings for cmps.nodes.CommandVariables variables: ['name', 'eclairPass', 'backendName', 'rpcUser', 'rpcPass'], From 5394aca5202dc89c570c99f27aafe8eb4db20146 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Tue, 24 Jun 2025 21:39:09 +0100 Subject: [PATCH 64/77] feat: add simln support to CLN --- .../designer/default/AddSimulationModal.tsx | 4 +- src/lib/docker/dockerService.spec.ts | 48 +++++++++++++++++-- src/lib/docker/dockerService.ts | 15 ++++++ src/lib/docker/nodeTemplates.ts | 1 + src/utils/constants.ts | 2 + 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/components/designer/default/AddSimulationModal.tsx b/src/components/designer/default/AddSimulationModal.tsx index b4341f1c52..9ef68a0f02 100644 --- a/src/components/designer/default/AddSimulationModal.tsx +++ b/src/components/designer/default/AddSimulationModal.tsx @@ -113,7 +113,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="source" label={l('source')} nodeStatus={Status.Started} - implementation={['LND', 'eclair']} + implementation={['LND', 'eclair', 'c-lightning']} nodes={nodes} /> @@ -123,7 +123,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="destination" label={l('destination')} nodeStatus={Status.Started} - implementation={['LND', 'eclair']} + implementation={['LND', 'eclair', 'c-lightning']} nodes={nodes} /> diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index 8a7cd8bd14..3f9ac72362 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -894,7 +894,7 @@ describe('DockerService', () => { name: 'my network', description: 'network description', lndNodes: 1, - clightningNodes: 0, + clightningNodes: 1, eclairNodes: 1, bitcoindNodes: 1, tapdNodes: 0, @@ -909,6 +909,9 @@ describe('DockerService', () => { const eclairNodes = network.nodes.lightning.filter( n => n.implementation === 'eclair', ); + const clightningNodes = network.nodes.lightning.filter( + n => n.implementation === 'c-lightning', + ); beforeEach(() => { // Add simulation config to the test network network.simulation = { @@ -974,9 +977,9 @@ describe('DockerService', () => { }); it('should handle errors when using unsupported node types', async () => { - network.nodes.lightning[0].implementation = 'c-lightning'; + network.nodes.lightning[0].implementation = 'litd'; await expect(dockerService.startSimulation(network)).rejects.toThrow( - 'unsupported node implementation: c-lightning', + 'unsupported node implementation: litd', ); }); @@ -1005,5 +1008,44 @@ describe('DockerService', () => { expect.stringContaining(`container_name: polar-n1-simln`), ); }); + + // Now we should be able to use c-lightning in the simulation + it('should add c-lightning to the docker-compose.yml file', async () => { + network.simulation = { + activity: [ + { + id: 0, + source: clightningNodes[0].name, + destination: eclairNodes[0].name, + intervalSecs: 60, + amountMsat: 1000, + }, + ], + status: Status.Stopped, + }; + dockerService.saveComposeFile(network); + expect(filesMock.write).toHaveBeenCalledWith( + expect.stringContaining('docker-compose.yml'), + expect.stringContaining(`container_name: polar-n1-simln`), + ); + + composeMock.upOne.mockResolvedValue(mockResult); + await dockerService.startSimulation(network); + + // Verify directories were created + expect(fsMock.ensureDir).toHaveBeenCalled(); + + // Verify sim.json was written with correct config + expect(filesMock.write).toHaveBeenCalledWith( + expect.stringContaining('sim.json'), + expect.stringContaining(clightningNodes[0].name), + ); + + // Verify docker compose command was called + expect(composeMock.upOne).toHaveBeenCalledWith( + 'simln', + expect.objectContaining({ cwd: network.path }), + ); + }); }); }); diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 97fdb152c9..1ee51e80a8 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -455,6 +455,21 @@ class DockerService implements DockerLibrary { }; break; + case 'c-lightning': + const cln = node as CLightningNode; + simNode = { + id: cln.name, + address: `host.docker.internal:${cln.ports.grpc}`, + ca_cert: `/home/simln/.${cln.paths.tlsCert?.split('volumes/').pop()}`, + client_cert: `/home/simln/.${cln.paths.tlsClientCert + ?.split('volumes/') + .pop()}`, + client_key: `/home/simln/.${cln.paths.tlsClientKey + ?.split('volumes/') + .pop()}`, + }; + break; + default: throw new Error(`unsupported node implementation: ${node.implementation}`); } diff --git a/src/lib/docker/nodeTemplates.ts b/src/lib/docker/nodeTemplates.ts index d2161c019b..bd26186e97 100644 --- a/src/lib/docker/nodeTemplates.ts +++ b/src/lib/docker/nodeTemplates.ts @@ -198,6 +198,7 @@ export const simln = ( volumes: [ `./volumes/${name}:/home/simln/.simln`, `./volumes/${dockerConfigs.LND.volumeDirName}:/home/simln/.lnd`, + `./volumes/${dockerConfigs['c-lightning'].volumeDirName}:/home/simln/.c-lightning`, ], expose: [], ports: [], diff --git a/src/utils/constants.ts b/src/utils/constants.ts index d8a98b456d..d2f2cf6375 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -193,6 +193,8 @@ export const dockerConfigs: Record = '--channel.max-htlc-value-in-flight-percent=100', '--channel.max-htlc-value-in-flight-msat=5000000000000', // 50 BTC in msats '--features.keysend=optional', + '--channel.min-final-expiry-delta-blocks=22', // Default is 30 for eclair, however it is 22 for CLN (the lowest). + '--channel.fulfill-safety-before-timeout-blocks=20', // When `channel.min-final-expiry-delta-blocks` is set, this is required and most be less than it. Default is 24. ].join('\n '), // if vars are modified, also update composeFile.ts & the i18n strings for cmps.nodes.CommandVariables variables: ['name', 'eclairPass', 'backendName', 'rpcUser', 'rpcPass'], From 4bf0102538fb90b42baffcafe1a8cd1b33c77fa6 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Thu, 18 Sep 2025 00:08:56 +0100 Subject: [PATCH 65/77] feat: add sim support to litd In the commit we add the sinln support to litd nodes. --- .../designer/default/AddSimulationModal.tsx | 4 ++-- src/lib/docker/dockerService.spec.ts | 14 ++++---------- src/lib/docker/dockerService.ts | 13 +++++++++++-- src/lib/docker/nodeTemplates.ts | 1 + 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/designer/default/AddSimulationModal.tsx b/src/components/designer/default/AddSimulationModal.tsx index 9ef68a0f02..838242fce4 100644 --- a/src/components/designer/default/AddSimulationModal.tsx +++ b/src/components/designer/default/AddSimulationModal.tsx @@ -113,7 +113,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="source" label={l('source')} nodeStatus={Status.Started} - implementation={['LND', 'eclair', 'c-lightning']} + implementation={['LND', 'eclair', 'c-lightning', 'litd']} nodes={nodes} /> @@ -123,7 +123,7 @@ const AddSimulationModal: React.FC = ({ network }) => { name="destination" label={l('destination')} nodeStatus={Status.Started} - implementation={['LND', 'eclair', 'c-lightning']} + implementation={['LND', 'eclair', 'c-lightning', 'litd']} nodes={nodes} /> diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index 3f9ac72362..f8fb4b242c 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -898,7 +898,7 @@ describe('DockerService', () => { eclairNodes: 1, bitcoindNodes: 1, tapdNodes: 0, - litdNodes: 0, + litdNodes: 1, repoState: defaultRepoState, managedImages: testManagedImages, customImages: [], @@ -912,6 +912,7 @@ describe('DockerService', () => { const clightningNodes = network.nodes.lightning.filter( n => n.implementation === 'c-lightning', ); + const litdNodes = network.nodes.lightning.filter(n => n.implementation === 'litd'); beforeEach(() => { // Add simulation config to the test network network.simulation = { @@ -976,13 +977,6 @@ describe('DockerService', () => { ); }); - it('should handle errors when using unsupported node types', async () => { - network.nodes.lightning[0].implementation = 'litd'; - await expect(dockerService.startSimulation(network)).rejects.toThrow( - 'unsupported node implementation: litd', - ); - }); - it('should handle errors when node is not found', async () => { network.simulation!.activity[0].source = 'non-existent'; await expect(dockerService.startSimulation(network)).rejects.toThrow( @@ -1009,14 +1003,14 @@ describe('DockerService', () => { ); }); - // Now we should be able to use c-lightning in the simulation + // Now we should be able to use c-lightning and litd in the simulation it('should add c-lightning to the docker-compose.yml file', async () => { network.simulation = { activity: [ { id: 0, source: clightningNodes[0].name, - destination: eclairNodes[0].name, + destination: litdNodes[0].name, intervalSecs: 60, amountMsat: 1000, }, diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 1ee51e80a8..83707393ad 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -470,8 +470,17 @@ class DockerService implements DockerLibrary { }; break; - default: - throw new Error(`unsupported node implementation: ${node.implementation}`); + case 'litd': + const litd = node as LitdNode; + simNode = { + id: litd.name, + address: `host.docker.internal:${litd.ports.grpc}`, + cert: `/home/simln/.${litd.paths.tlsCert.split('volumes/').pop()}`, + macaroon: `/home/simln/.${litd.paths.adminMacaroon + .split('volumes/') + .pop()}`, + }; + break; } // Add the node to the nodes Set. diff --git a/src/lib/docker/nodeTemplates.ts b/src/lib/docker/nodeTemplates.ts index bd26186e97..1abba77ca9 100644 --- a/src/lib/docker/nodeTemplates.ts +++ b/src/lib/docker/nodeTemplates.ts @@ -199,6 +199,7 @@ export const simln = ( `./volumes/${name}:/home/simln/.simln`, `./volumes/${dockerConfigs.LND.volumeDirName}:/home/simln/.lnd`, `./volumes/${dockerConfigs['c-lightning'].volumeDirName}:/home/simln/.c-lightning`, + `./volumes/${dockerConfigs.litd.volumeDirName}:/home/simln/.litd`, ], expose: [], ports: [], From 9614295f5e3e3c25f7ca31c48a3f62b04fb697d0 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Sat, 27 Sep 2025 12:18:04 +0100 Subject: [PATCH 66/77] docs: add docker build command to readme --- docker/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docker/README.md b/docker/README.md index d710f2d16f..f5216fe6c0 100644 --- a/docker/README.md +++ b/docker/README.md @@ -221,6 +221,21 @@ $ docker buildx build --platform linux/amd64,linux/arm64 --build-arg LITD_VERSIO Replace `` with the desired Tap version (ex: `0.13.3-alpha`). +## SimLN + +### Tags + +- `0.2.5` ([simln/Dockerfile](https://github.com/jamaljsr/polar/blob/master/docker/simln/Dockerfile)) + +**Building the image** + +```sh +$ cd simln +$ docker buildx build --platform linux/amd64, linux/arm64 --build-arg SIMLN_VERSION= -t polarlightning/simln: --push . +``` + +Replace `` with the desired SimLN version (ex: `0.2.5`). + # Out-of-Band Image Updates > Note: These steps can only be performed by developers with commit access to this GitHub repo and push access to the Docker Hub repo From dcd249559d6ffbf5f1b0d9afd4001478ff976263 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Tue, 7 Oct 2025 20:05:21 +0100 Subject: [PATCH 67/77] fix: format windows path to POSIX --- src/lib/docker/dockerService.spec.ts | 34 ++++++++++++++++++++++++++++ src/lib/docker/dockerService.ts | 29 +++++++++++++----------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index f8fb4b242c..8f2a4664f4 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -1041,5 +1041,39 @@ describe('DockerService', () => { expect.objectContaining({ cwd: network.path }), ); }); + + it('should map windows paths to posix paths', () => { + // Mock Windows-style absolute paths. + const lnd = lndNodes[0] as LndNode; + const windowsPath = `C:\\Users\\username\\.polar\\networks\\${network.id}\\volumes\\lnd\\${lnd.name}`; + + const tlsCertPath = `${windowsPath}\\tls.cert`; + const macaroonPath = `${windowsPath}\\data\\chain\\bitcoin\\regtest\\admin.macaroon`; + + lnd.paths.tlsCert = tlsCertPath; + lnd.paths.adminMacaroon = macaroonPath; + + network.simulation = { + activity: [ + { + id: 0, + source: lndNodes[0].name, + destination: eclairNodes[0].name, + intervalSecs: 60, + amountMsat: 1000, + }, + ], + status: Status.Stopped, + }; + + const simJson = dockerService.constructSimJson(network); + + const lndNode = simJson.nodes.find(n => n.id === lnd.name); + expect(lndNode).toBeDefined(); + expect(lndNode?.cert).toBe(`/home/simln/.lnd/${lnd.name}/tls.cert`); + expect(lndNode?.macaroon).toBe( + `/home/simln/.lnd/${lnd.name}/data/chain/bitcoin/regtest/admin.macaroon`, + ); + }); }); }); diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 83707393ad..12179843d8 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -405,6 +405,15 @@ class DockerService implements DockerLibrary { * @param network the network to start */ constructSimJson(network: Network) { + // Helper function to convert Windows paths to POSIX path format. + const getPosixPath = (path: string) => { + // Normalize to POSIX separators for Windows paths. + const norm = path.replace(/\\/g, '/'); + + const parts = norm.split('volumes/'); + + return parts[parts.length - 1]; + }; const simJson: { nodes: SimulationNodeConfig[]; activity: ActivityConfig[]; @@ -439,9 +448,9 @@ class DockerService implements DockerLibrary { const lnd = node as LndNode; simNode = { id: lnd.name, - macaroon: `/home/simln/.${lnd.paths.adminMacaroon.split('volumes/').pop()}`, + macaroon: `/home/simln/.${getPosixPath(lnd.paths.adminMacaroon)}`, address: `https://host.docker.internal:${lnd.ports.grpc}`, - cert: `/home/simln/.${lnd.paths.tlsCert.split('volumes/').pop()}`, + cert: `/home/simln/.${getPosixPath(lnd.paths.tlsCert)}`, }; break; @@ -460,13 +469,9 @@ class DockerService implements DockerLibrary { simNode = { id: cln.name, address: `host.docker.internal:${cln.ports.grpc}`, - ca_cert: `/home/simln/.${cln.paths.tlsCert?.split('volumes/').pop()}`, - client_cert: `/home/simln/.${cln.paths.tlsClientCert - ?.split('volumes/') - .pop()}`, - client_key: `/home/simln/.${cln.paths.tlsClientKey - ?.split('volumes/') - .pop()}`, + ca_cert: `/home/simln/.${getPosixPath(cln.paths.tlsCert!)}`, + client_cert: `/home/simln/.${getPosixPath(cln.paths.tlsClientCert!)}`, + client_key: `/home/simln/.${getPosixPath(cln.paths.tlsClientKey!)}`, }; break; @@ -475,10 +480,8 @@ class DockerService implements DockerLibrary { simNode = { id: litd.name, address: `host.docker.internal:${litd.ports.grpc}`, - cert: `/home/simln/.${litd.paths.tlsCert.split('volumes/').pop()}`, - macaroon: `/home/simln/.${litd.paths.adminMacaroon - .split('volumes/') - .pop()}`, + cert: `/home/simln/.${getPosixPath(litd.paths.tlsCert)}`, + macaroon: `/home/simln/.${getPosixPath(litd.paths.adminMacaroon)}`, }; break; } From 390411783d40ba8fd4f99572cb19cba2177b0232 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:48:47 -0600 Subject: [PATCH 68/77] fix(simln): resolve simln issues on linux --- src/lib/docker/dockerService.spec.ts | 27 +++++++++++++++++++++++ src/lib/docker/dockerService.ts | 33 ++++++++++++++++++---------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/lib/docker/dockerService.spec.ts b/src/lib/docker/dockerService.spec.ts index 8f2a4664f4..d7587b445f 100644 --- a/src/lib/docker/dockerService.spec.ts +++ b/src/lib/docker/dockerService.spec.ts @@ -1075,5 +1075,32 @@ describe('DockerService', () => { `/home/simln/.lnd/${lnd.name}/data/chain/bitcoin/regtest/admin.macaroon`, ); }); + + it('should handle missing c-lightning paths', () => { + const net = getNetwork(); + const cln = net.nodes.lightning.filter( + n => n.implementation === 'c-lightning', + )[0] as CLightningNode; + cln.paths.tlsCert = undefined; + cln.paths.tlsClientCert = undefined; + cln.paths.tlsClientKey = undefined; + net.simulation = { + activity: [ + { + id: 0, + source: cln.name, + destination: net.nodes.lightning[0].name, + intervalSecs: 60, + amountMsat: 1000, + }, + ], + status: Status.Stopped, + }; + const simJson = dockerService.constructSimJson(net); + const clnSimNode = simJson.nodes.find(n => n.id === cln.name); + expect(clnSimNode?.ca_cert).toBeDefined(); + expect(clnSimNode?.client_cert).toBeDefined(); + expect(clnSimNode?.client_key).toBeDefined(); + }); }); }); diff --git a/src/lib/docker/dockerService.ts b/src/lib/docker/dockerService.ts index 12179843d8..30d48d899e 100644 --- a/src/lib/docker/dockerService.ts +++ b/src/lib/docker/dockerService.ts @@ -19,17 +19,18 @@ import { } from 'shared/types'; import stripAnsi from 'strip-ansi'; import { + ActivityConfig, DockerLibrary, DockerVersions, Network, NetworksFile, - ActivityConfig, SimulationNodeConfig, } from 'types'; import { legacyDataPath, networksPath, nodePath } from 'utils/config'; import { APP_VERSION, dockerConfigs, eclairCredentials } from 'utils/constants'; import { exists, read, renameFile, rm, write } from 'utils/files'; import { migrateNetworksFile } from 'utils/migrations'; +import { getContainerName } from 'utils/network'; import { isLinux, isMac } from 'utils/system'; import ComposeFile from './composeFile'; @@ -406,7 +407,7 @@ class DockerService implements DockerLibrary { */ constructSimJson(network: Network) { // Helper function to convert Windows paths to POSIX path format. - const getPosixPath = (path: string) => { + const getPosixPath = (path = '') => { // Normalize to POSIX separators for Windows paths. const norm = path.replace(/\\/g, '/'); @@ -449,7 +450,7 @@ class DockerService implements DockerLibrary { simNode = { id: lnd.name, macaroon: `/home/simln/.${getPosixPath(lnd.paths.adminMacaroon)}`, - address: `https://host.docker.internal:${lnd.ports.grpc}`, + address: `https://${getContainerName(node)}:10009`, cert: `/home/simln/.${getPosixPath(lnd.paths.tlsCert)}`, }; break; @@ -458,7 +459,7 @@ class DockerService implements DockerLibrary { const eclair = node as EclairNode; simNode = { id: eclair.name, - base_url: `http://host.docker.internal:${eclair.ports.rest}`, + base_url: `http://${getContainerName(node)}:8080`, api_username: '', api_password: eclairCredentials.pass, }; @@ -468,10 +469,10 @@ class DockerService implements DockerLibrary { const cln = node as CLightningNode; simNode = { id: cln.name, - address: `host.docker.internal:${cln.ports.grpc}`, - ca_cert: `/home/simln/.${getPosixPath(cln.paths.tlsCert!)}`, - client_cert: `/home/simln/.${getPosixPath(cln.paths.tlsClientCert!)}`, - client_key: `/home/simln/.${getPosixPath(cln.paths.tlsClientKey!)}`, + address: `${getContainerName(node)}:11001`, + ca_cert: `/home/simln/.${getPosixPath(cln.paths.tlsCert)}`, + client_cert: `/home/simln/.${getPosixPath(cln.paths.tlsClientCert)}`, + client_key: `/home/simln/.${getPosixPath(cln.paths.tlsClientKey)}`, }; break; @@ -479,7 +480,7 @@ class DockerService implements DockerLibrary { const litd = node as LitdNode; simNode = { id: litd.name, - address: `host.docker.internal:${litd.ports.grpc}`, + address: `${getContainerName(node)}:10009`, cert: `/home/simln/.${getPosixPath(litd.paths.tlsCert)}`, macaroon: `/home/simln/.${getPosixPath(litd.paths.adminMacaroon)}`, }; @@ -516,14 +517,22 @@ class DockerService implements DockerLibrary { * @param network the network containing the simulation */ async startSimulation(network: Network) { - const simJson = this.constructSimJson(network); await this.ensureDirs(network, [ ...network.nodes.bitcoin, ...network.nodes.lightning, ...network.nodes.tap, ]); - const simjsonPath = nodePath(network, 'simln', 'sim.json'); - await write(simjsonPath, JSON.stringify(simJson)); + // we need to create this dir as the current host user, otherwise it will be created + // by the simln container and the owner will be set to root on linux. This prevents + // deleting the network due to file permission errors. + await ensureDir(nodePath(network, 'simln', 'results')); + + // save the sim.json file for the simulation + const simJson = this.constructSimJson(network); + const simJsonPath = nodePath(network, 'simln', 'sim.json'); + await write(simJsonPath, JSON.stringify(simJson)); + + // start the simln container const result = await this.execute(compose.upOne, 'simln', this.getArgs(network)); info(`Simulation started:\n ${result.out || result.err}`); } From ac4038696dbb190e257e2134a9123de59a1b7520 Mon Sep 17 00:00:00 2001 From: jamaljsr <1356600+jamaljsr@users.noreply.github.com> Date: Wed, 3 Dec 2025 23:29:55 -0600 Subject: [PATCH 69/77] fix(simln): improve simulations UI --- .../designer/default/DefaultSidebar.spec.tsx | 8 +++++-- .../default/SimulationDesignerTab.tsx | 23 +++++++++++++------ src/i18n/locales/en-US.json | 7 +++--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/components/designer/default/DefaultSidebar.spec.tsx b/src/components/designer/default/DefaultSidebar.spec.tsx index 589f2c9eba..681945a72f 100644 --- a/src/components/designer/default/DefaultSidebar.spec.tsx +++ b/src/components/designer/default/DefaultSidebar.spec.tsx @@ -129,7 +129,11 @@ describe('DefaultSidebar Component', () => { it('should display the Simulation Designer Tab', () => { const { getByText } = renderComponent(); - fireEvent.click(getByText('Simulation Designer')); - expect(getByText('Lightning Network Simulation')).toBeInTheDocument(); + fireEvent.click(getByText('Simulations')); + expect( + getByText( + 'Automate Lightning payments between nodes by adding simulation activities below.', + ), + ).toBeInTheDocument(); }); }); diff --git a/src/components/designer/default/SimulationDesignerTab.tsx b/src/components/designer/default/SimulationDesignerTab.tsx index 1f0ace72f4..bd4f53e6fe 100644 --- a/src/components/designer/default/SimulationDesignerTab.tsx +++ b/src/components/designer/default/SimulationDesignerTab.tsx @@ -1,17 +1,18 @@ import React, { ReactNode, useCallback, useEffect } from 'react'; -import styled from '@emotion/styled'; -import { usePrefixedTranslation } from 'hooks'; -import { Button, Empty, Modal, Tooltip, MenuProps, Dropdown, Alert } from 'antd'; +import { useAsyncCallback } from 'react-async-hook'; import { ArrowRightOutlined, - PlusOutlined, CloseOutlined, MoreOutlined, + PlusOutlined, } from '@ant-design/icons'; +import styled from '@emotion/styled'; +import { Alert, Button, Dropdown, Empty, MenuProps, Modal, Tooltip } from 'antd'; +import { usePrefixedTranslation } from 'hooks'; +import { Status } from 'shared/types'; import { useStoreActions, useStoreState } from 'store'; import { Network } from 'types'; -import { useAsyncCallback } from 'react-async-hook'; -import { Status } from 'shared/types'; +import { abbreviate } from 'utils/numbers'; import StatusButton from 'components/common/StatusButton'; interface Props { @@ -43,9 +44,13 @@ const Styled = { display: flex; align-items: center; justify-content: start; - column-gap: 15px; + column-gap: 10px; width: 100%; `, + ActivityDetails: styled.span` + opacity: 0.5; + font-size: 12px; + `, Dropdown: styled(Dropdown)` margin-left: 12px; `, @@ -164,6 +169,9 @@ const SimulationDesignerTab: React.FC = ({ network }) => { {a.source} {a.destination} + + {abbreviate(a.amountMsat / 1000)} sats / {a.intervalSecs}s + = ({ network }) => { return (
+

{l('mainDesc')}

{l('title')} diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 5460f46bd3..4e1c9fa782 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -113,13 +113,14 @@ "cmps.designer.bitcoind.actions.SendOnChainModal.successTitle": "Successfully sent {{amount}} BTC", "cmps.designer.bitcoind.actions.SendOnChainModal.successDesc": "Transaction ID: {{txid}}", "cmps.designer.default.DefaultSidebar.networkTabTitle": "Network Designer", + "cmps.designer.default.DefaultSidebar.simulationTabTitle": "Simulations", "cmps.designer.default.NetworkDesignerTab.mainDesc": "Click on an element in the designer to see details", "cmps.designer.default.NetworkDesignerTab.addNodesTitle": "Add Nodes", "cmps.designer.default.NetworkDesignerTab.addNodesDesc": "Drag a node below onto the canvas to add it to the network", "cmps.designer.default.NetworkDesignerTab.checkUpdates": "Check for new Node Versions", - "cmps.designer.default.DefaultSidebar.simulationTabTitle": "Simulation Designer", + "cmps.designer.default.SimulationDesignerTab.mainDesc": "Automate Lightning payments between nodes by adding simulation activities below.", "cmps.designer.default.SimulationDesignerTab.createBtn": "Add a new Simulation", - "cmps.designer.default.SimulationDesignerTab.title": "Lightning Network Simulation", + "cmps.designer.default.SimulationDesignerTab.title": "Simulations", "cmps.designer.default.SimulationDesignerTab.emptyMsg": "No simulations created yet", "cmps.designer.default.SimulationDesignerTab.noActivities": "No activities added yet.", "cmps.designer.default.SimulationDesignerTab.removeTitle": "Remove Simulation", @@ -135,7 +136,7 @@ "cmps.designer.default.SimulationDesignerTab.primaryBtnRestart": "Restart", "cmps.designer.default.SimulationDesignerTab.startError": "Unable to start the simulation", "cmps.designer.default.SimulationDesignerTab.stopError": "Unable to stop the simulation", - "cmps.designer.default.SimulationDesignerTab.networkNotStarted": "Network must be started to add simulations", + "cmps.designer.default.SimulationDesignerTab.networkNotStarted": "Start the network to add simulations.", "cmps.designer.default.AddSimulationModal.title": "Add Simulation", "cmps.designer.default.AddSimulationModal.cancelBtn": "Cancel", "cmps.designer.default.AddSimulationModal.createBtn": "Create", From 1bb9f95b47e07e76cc790ad6f4dc1ddde4197b87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:45:16 +0000 Subject: [PATCH 70/77] chore(deps): update rust docker tag to v1.91.1 (#1333) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/simln/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/simln/Dockerfile b/docker/simln/Dockerfile index 51e11f9c32..b8dcce0b25 100644 --- a/docker/simln/Dockerfile +++ b/docker/simln/Dockerfile @@ -2,7 +2,7 @@ # Original Source: https://github.com/bitcoin-dev-project/sim-ln/blob/main/docker/Dockerfile # Use the rust image as the base image for the build stage -FROM rust:1.85.0 AS base +FROM rust:1.91.1 AS base # buildkit will provide this automatically, no need to pass it in ARG TARGETARCH From b77d80c077fbfdc24b73045841d6ccd31ea15c62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 22:08:58 +0000 Subject: [PATCH 71/77] chore(deps): update node.js to 9632533 (#1334) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/litd/src.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/litd/src.Dockerfile b/docker/litd/src.Dockerfile index 4d373088b6..ecb5d587fe 100644 --- a/docker/litd/src.Dockerfile +++ b/docker/litd/src.Dockerfile @@ -1,5 +1,5 @@ # Start with a NodeJS base image that also contains yarn. -FROM node:22.21.1-alpine@sha256:b2358485e3e33bc3a33114d2b1bdb18cdbe4df01bd2b257198eb51beb1f026c5 as nodejsbuilder +FROM node:22.21.1-alpine@sha256:9632533eda8061fc1e9960cfb3f8762781c07a00ee7317f5dc0e13c05e15166f as nodejsbuilder ARG LITD_VERSION From b2b03d0988d1a2a0914d6e89797c5220f3a49b3b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Dec 2025 01:55:11 +0000 Subject: [PATCH 72/77] chore(deps): update commitlint monorepo to v20.2.0 (#1335) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- yarn.lock | 152 +++++++++++++++++++++++++-------------------------- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index b70bbef066..75bd5624f7 100644 --- a/package.json +++ b/package.json @@ -65,8 +65,8 @@ "devDependencies": { "@ant-design/icons": "5.6.1", "@babel/plugin-proposal-private-property-in-object": "7.21.11", - "@commitlint/cli": "20.1.0", - "@commitlint/config-conventional": "20.0.0", + "@commitlint/cli": "20.2.0", + "@commitlint/config-conventional": "20.2.0", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", "@emotion/styled": "11.14.1", diff --git a/yarn.lock b/yarn.lock index c1261fdf7f..373f36d819 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1544,25 +1544,25 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@commitlint/cli@20.1.0": - version "20.1.0" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-20.1.0.tgz#07365e2849d86f771e76ea0ceb96cd88bb945e03" - integrity sha512-pW5ujjrOovhq5RcYv5xCpb4GkZxkO2+GtOdBW2/qrr0Ll9tl3PX0aBBobGQl3mdZUbOBgwAexEQLeH6uxL0VYg== - dependencies: - "@commitlint/format" "^20.0.0" - "@commitlint/lint" "^20.0.0" - "@commitlint/load" "^20.1.0" - "@commitlint/read" "^20.0.0" - "@commitlint/types" "^20.0.0" +"@commitlint/cli@20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-20.2.0.tgz#4164499d3848447aacd795d298c8a768fb13a80c" + integrity sha512-l37HkrPZ2DZy26rKiTUvdq/LZtlMcxz+PeLv9dzK9NzoFGuJdOQyYU7IEkEQj0pO++uYue89wzOpZ0hcTtoqUA== + dependencies: + "@commitlint/format" "^20.2.0" + "@commitlint/lint" "^20.2.0" + "@commitlint/load" "^20.2.0" + "@commitlint/read" "^20.2.0" + "@commitlint/types" "^20.2.0" tinyexec "^1.0.0" yargs "^17.0.0" -"@commitlint/config-conventional@20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-20.0.0.tgz#f222dc9ce08e16f9c66eae55e99129d2be517546" - integrity sha512-q7JroPIkDBtyOkVe9Bca0p7kAUYxZMxkrBArCfuD3yN4KjRAenP9PmYwnn7rsw8Q+hHq1QB2BRmBh0/Z19ZoJw== +"@commitlint/config-conventional@20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-20.2.0.tgz#3c53c9d2939a0cc5ef8ef1f2c682eab2484e860e" + integrity sha512-MsRac+yNIbTB4Q/psstKK4/ciVzACHicSwz+04Sxve+4DW+PiJeTjU0JnS4m/oOnulrXYN+yBPlKaBSGemRfgQ== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" conventional-changelog-conventionalcommits "^7.0.2" "@commitlint/config-validator@^18.4.4": @@ -1573,20 +1573,20 @@ "@commitlint/types" "^18.4.4" ajv "^8.11.0" -"@commitlint/config-validator@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-20.0.0.tgz#d97d83be722a04be2038e54bdd3ec7d11efec557" - integrity sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg== +"@commitlint/config-validator@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-20.2.0.tgz#5f5cbad01d5ed2b67cc2363143ccc7de8bca3173" + integrity sha512-SQCBGsL9MFk8utWNSthdxd9iOD1pIVZSHxGBwYIGfd67RTjxqzFOSAYeQVXOu3IxRC3YrTOH37ThnTLjUlyF2w== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" ajv "^8.11.0" -"@commitlint/ensure@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-20.0.0.tgz#f97c16f53c0f7ea79895f9a19e5dad5213353aef" - integrity sha512-WBV47Fffvabe68n+13HJNFBqiMH5U1Ryls4W3ieGwPC0C7kJqp3OVQQzG2GXqOALmzrgAB+7GXmyy8N9ct8/Fg== +"@commitlint/ensure@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-20.2.0.tgz#6b4ae312aea8397f6e3171bbd6bade3f6b2ad8e5" + integrity sha512-+8TgIGv89rOWyt3eC6lcR1H7hqChAKkpawytlq9P1i/HYugFRVqgoKJ8dhd89fMnlrQTLjA5E97/4sF09QwdoA== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" lodash.camelcase "^4.3.0" lodash.kebabcase "^4.1.1" lodash.snakecase "^4.1.1" @@ -1603,31 +1603,31 @@ resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz#013628e09179cf2d3c977e1cf37937b5cb869af8" integrity sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw== -"@commitlint/format@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-20.0.0.tgz#46c9c032bb02511f4a88d82460d036bd555a1940" - integrity sha512-zrZQXUcSDmQ4eGGrd+gFESiX0Rw+WFJk7nW4VFOmxub4mAATNKBQ4vNw5FgMCVehLUKG2OT2LjOqD0Hk8HvcRg== +"@commitlint/format@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-20.2.0.tgz#0f54ee9617a2298c540de331bc8642ff70c331a1" + integrity sha512-PhNoLNhxpfIBlW/i90uZ3yG3hwSSYx7n4d9Yc+2FAorAHS0D9btYRK4ZZXX+Gm3W5tDtu911ow/eWRfcRVgNWg== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" chalk "^5.3.0" -"@commitlint/is-ignored@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-20.0.0.tgz#80157d00985e698364d92bc63bf5bb2730a0c7d2" - integrity sha512-ayPLicsqqGAphYIQwh9LdAYOVAQ9Oe5QCgTNTj+BfxZb9b/JW222V5taPoIBzYnAP0z9EfUtljgBk+0BN4T4Cw== +"@commitlint/is-ignored@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-20.2.0.tgz#a6754daffb928d5689148e837106bb38dcc0c164" + integrity sha512-Lz0OGeZCo/QHUDLx5LmZc0EocwanneYJUM8z0bfWexArk62HKMLfLIodwXuKTO5y0s6ddXaTexrYHs7v96EOmw== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" semver "^7.6.0" -"@commitlint/lint@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-20.0.0.tgz#3f61ebb1c7c69b82ad3f43cfcf91ce318b1a5c3a" - integrity sha512-kWrX8SfWk4+4nCexfLaQT3f3EcNjJwJBsSZ5rMBw6JCd6OzXufFHgel2Curos4LKIxwec9WSvs2YUD87rXlxNQ== +"@commitlint/lint@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-20.2.0.tgz#535f63f419cef7244b0a2907b5bf27ecb1f55bda" + integrity sha512-cQEEB+jlmyQbyiji/kmh8pUJSDeUmPiWq23kFV0EtW3eM+uAaMLMuoTMajbrtWYWQpPzOMDjYltQ8jxHeHgITg== dependencies: - "@commitlint/is-ignored" "^20.0.0" - "@commitlint/parse" "^20.0.0" - "@commitlint/rules" "^20.0.0" - "@commitlint/types" "^20.0.0" + "@commitlint/is-ignored" "^20.2.0" + "@commitlint/parse" "^20.2.0" + "@commitlint/rules" "^20.2.0" + "@commitlint/types" "^20.2.0" "@commitlint/load@>6.1.1": version "18.4.4" @@ -1646,15 +1646,15 @@ lodash.uniq "^4.5.0" resolve-from "^5.0.0" -"@commitlint/load@^20.1.0": - version "20.1.0" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-20.1.0.tgz#8eb7aefbfb066db903d1a89c4727093a57fcffbc" - integrity sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg== +"@commitlint/load@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-20.2.0.tgz#0864d7296c9dc7f0759c811e7e497e2df03292db" + integrity sha512-iAK2GaBM8sPFTSwtagI67HrLKHIUxQc2BgpgNc/UMNme6LfmtHpIxQoN1TbP+X1iz58jq32HL1GbrFTCzcMi6g== dependencies: - "@commitlint/config-validator" "^20.0.0" + "@commitlint/config-validator" "^20.2.0" "@commitlint/execute-rule" "^20.0.0" - "@commitlint/resolve-extends" "^20.1.0" - "@commitlint/types" "^20.0.0" + "@commitlint/resolve-extends" "^20.2.0" + "@commitlint/types" "^20.2.0" chalk "^5.3.0" cosmiconfig "^9.0.0" cosmiconfig-typescript-loader "^6.1.0" @@ -1667,22 +1667,22 @@ resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-20.0.0.tgz#a5ac95dc17363a1dba5d2d47bd28c9356710a7b8" integrity sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ== -"@commitlint/parse@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-20.0.0.tgz#a056ec3c25401dfc9905196e159aaee3a2dfdf43" - integrity sha512-j/PHCDX2bGM5xGcWObOvpOc54cXjn9g6xScXzAeOLwTsScaL4Y+qd0pFC6HBwTtrH92NvJQc+2Lx9HFkVi48cg== +"@commitlint/parse@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-20.2.0.tgz#76a44b8426db9257dd9408dace4eb8f02f3a3983" + integrity sha512-LXStagGU1ivh07X7sM+hnEr4BvzFYn1iBJ6DRg2QsIN8lBfSzyvkUcVCDwok9Ia4PWiEgei5HQjju6xfJ1YaSQ== dependencies: - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" conventional-changelog-angular "^7.0.0" conventional-commits-parser "^5.0.0" -"@commitlint/read@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-20.0.0.tgz#6c22541109176878d533c396860d26ad8ec3d74f" - integrity sha512-Ti7Y7aEgxsM1nkwA4ZIJczkTFRX/+USMjNrL9NXwWQHqNqrBX2iMi+zfuzZXqfZ327WXBjdkRaytJ+z5vNqTOA== +"@commitlint/read@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-20.2.0.tgz#6637b53fc5e5b19ecbf65c61ff77732a87d11016" + integrity sha512-+SjF9mxm5JCbe+8grOpXCXMMRzAnE0WWijhhtasdrpJoAFJYd5UgRTj/oCq5W3HJTwbvTOsijEJ0SUGImECD7Q== dependencies: "@commitlint/top-level" "^20.0.0" - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" git-raw-commits "^4.0.0" minimist "^1.2.8" tinyexec "^1.0.0" @@ -1699,27 +1699,27 @@ resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/resolve-extends@^20.1.0": - version "20.1.0" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-20.1.0.tgz#bfccbd7772ffa49f99f3e0f828cf8612667b2e8e" - integrity sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw== +"@commitlint/resolve-extends@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-20.2.0.tgz#7c4c99a239dad83a11fed7d1a9a573731cc57c5e" + integrity sha512-KVoLDi9BEuqeq+G0wRABn4azLRiCC22/YHR2aCquwx6bzCHAIN8hMt3Nuf1VFxq/c8ai6s8qBxE8+ZD4HeFTlQ== dependencies: - "@commitlint/config-validator" "^20.0.0" - "@commitlint/types" "^20.0.0" + "@commitlint/config-validator" "^20.2.0" + "@commitlint/types" "^20.2.0" global-directory "^4.0.1" import-meta-resolve "^4.0.0" lodash.mergewith "^4.6.2" resolve-from "^5.0.0" -"@commitlint/rules@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-20.0.0.tgz#d5793a9435313182477456a317822874232b7d0f" - integrity sha512-gvg2k10I/RfvHn5I5sxvVZKM1fl72Sqrv2YY/BnM7lMHcYqO0E2jnRWoYguvBfEcZ39t+rbATlciggVe77E4zA== +"@commitlint/rules@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-20.2.0.tgz#0fd03c9bf55dccd3ddc1948f6ea36cd5ed162e8d" + integrity sha512-27rHGpeAjnYl/A+qUUiYDa7Yn1WIjof/dFJjYW4gA1Ug+LUGa1P0AexzGZ5NBxTbAlmDgaxSZkLLxtLVqtg8PQ== dependencies: - "@commitlint/ensure" "^20.0.0" + "@commitlint/ensure" "^20.2.0" "@commitlint/message" "^20.0.0" "@commitlint/to-lines" "^20.0.0" - "@commitlint/types" "^20.0.0" + "@commitlint/types" "^20.2.0" "@commitlint/to-lines@^20.0.0": version "20.0.0" @@ -1740,10 +1740,10 @@ dependencies: chalk "^4.1.0" -"@commitlint/types@^20.0.0": - version "20.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-20.0.0.tgz#70edef6e1c1d3aaca15e1e87242d8d256beebe67" - integrity sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA== +"@commitlint/types@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-20.2.0.tgz#8486ef31ecfc7b4d10f8bf5c47934872bcd8657e" + integrity sha512-KTy0OqRDLR5y/zZMnizyx09z/rPlPC/zKhYgH8o/q6PuAjoQAKlRfY4zzv0M64yybQ//6//4H1n14pxaLZfUnA== dependencies: "@types/conventional-commits-parser" "^5.0.0" chalk "^5.3.0" From cee4d6343f0bda972f0078198e4a42e35adc788a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Dec 2025 06:05:09 +0000 Subject: [PATCH 73/77] chore(deps): update rust docker tag to v1.92.0 (#1337) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/simln/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/simln/Dockerfile b/docker/simln/Dockerfile index b8dcce0b25..f53bd78454 100644 --- a/docker/simln/Dockerfile +++ b/docker/simln/Dockerfile @@ -2,7 +2,7 @@ # Original Source: https://github.com/bitcoin-dev-project/sim-ln/blob/main/docker/Dockerfile # Use the rust image as the base image for the build stage -FROM rust:1.91.1 AS base +FROM rust:1.92.0 AS base # buildkit will provide this automatically, no need to pass it in ARG TARGETARCH From a94762d72975e6bbe7e8ae1ab7b50cc4ce3d554a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 02:48:51 +0000 Subject: [PATCH 74/77] chore(deps): update dependency less to v4.5.1 (#1338) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 75bd5624f7..9cd292d62b 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "jest-canvas-mock": "2.5.2", "jest-environment-jsdom-sixteen": "2.0.0", "js-yaml": "4.1.1", - "less": "4.4.2", + "less": "4.5.1", "less-loader": "12.3.0", "lint-staged": "16.2.7", "lndconnect": "0.2.10", diff --git a/yarn.lock b/yarn.lock index 373f36d819..077a9c6370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13198,10 +13198,10 @@ less-loader@12.3.0: resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-12.3.0.tgz#d4a00361568be86a97da3df4f16954b0d4c15340" integrity sha512-0M6+uYulvYIWs52y0LqN4+QM9TqWAohYSNTo4htE8Z7Cn3G/qQMEmktfHmyJT23k+20kU9zHH2wrfFXkxNLtVw== -less@4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/less/-/less-4.4.2.tgz#fa4291fdb0334de91163622cc038f4bd3eb6b8d7" - integrity sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g== +less@4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/less/-/less-4.5.1.tgz#739266532249a3de232e8b60ffb1b27ad5ec6ad8" + integrity sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw== dependencies: copy-anything "^2.0.1" parse-node-version "^1.0.1" From a6feb977cb85b91e47a9e0b66ae6efb58d04898d Mon Sep 17 00:00:00 2001 From: JC Brand Date: Thu, 18 Sep 2025 11:05:38 +0200 Subject: [PATCH 75/77] fix: tsc compilation error ``` [app] src/lib/lightning/types.ts [app] Line 89:18: An interface declaring no members is equivalent to its supertype @typescript-eslint/no-empty-interface ``` --- src/lib/lightning/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/lightning/types.ts b/src/lib/lightning/types.ts index bfaceff08f..4e1b282b5d 100644 --- a/src/lib/lightning/types.ts +++ b/src/lib/lightning/types.ts @@ -80,4 +80,4 @@ export interface LightningNodeChannelEvent { type: 'Open' | 'Pending' | 'Closed' | 'Unknown'; } -export interface CustomRecords extends Record {} +export type CustomRecords = Record; From 0cb5e370bbfa657fdb5955b417aa1ba86bb836fe Mon Sep 17 00:00:00 2001 From: JC Brand Date: Thu, 18 Sep 2025 10:58:52 +0200 Subject: [PATCH 76/77] feat: allow self-payment for invoices Adds an "Advanced Options" section with a checkbox where you can choose to allow self-payments. --- .../actions/PayInvoiceModal.spec.tsx | 25 +++++++++++++++++ .../lightning/actions/PayInvoiceModal.tsx | 28 ++++++++++++++++--- src/i18n/locales/en-US.json | 2 ++ src/lib/lightning/lnd/lndService.spec.ts | 28 +++++++++++++++++++ src/lib/lightning/lnd/lndService.ts | 4 ++- src/lib/lightning/types.ts | 6 ++++ src/lib/tap/tapd/tapdService.ts | 2 ++ src/store/models/lightning.ts | 20 +++++++++---- src/store/models/lit.ts | 4 ++- src/types/index.ts | 2 ++ 10 files changed, 109 insertions(+), 12 deletions(-) diff --git a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx index 7d3c97c79f..f20abe3b7f 100644 --- a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx +++ b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx @@ -201,6 +201,31 @@ describe('PayInvoiceModal', () => { 'lnbc1', 400000, '', + undefined, + ); + }); + + it('should pay invoice with allowSelfPayment option', async () => { + const { findByText, getByText, getByLabelText, store, changeSelect } = + await renderComponent('bob'); + expect(await findByText('From Node')).toBeInTheDocument(); + fireEvent.change(getByLabelText('BOLT 11 Invoice'), { target: { value: 'lnbc1' } }); + changeSelect('Asset to Send', 'test asset'); + fireEvent.click(getByText('Advanced Options')); + fireEvent.click(getByLabelText('Allow self-payment')); + fireEvent.click(getByText('Pay Invoice')); + await waitFor(() => { + expect(store.getState().modals.payInvoice.visible).toBe(false); + }); + const node = network.nodes.lightning[1]; + const tapdNode = mapToTapd(node); + expect(tapServiceMock.sendPayment).toHaveBeenCalledWith( + tapdNode, + 'abcd', + 'lnbc1', + 400000, + '', + true, ); }); }); diff --git a/src/components/designer/lightning/actions/PayInvoiceModal.tsx b/src/components/designer/lightning/actions/PayInvoiceModal.tsx index 3f76a7a11b..1d11218398 100644 --- a/src/components/designer/lightning/actions/PayInvoiceModal.tsx +++ b/src/components/designer/lightning/actions/PayInvoiceModal.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { useAsync, useAsyncCallback } from 'react-async-hook'; import styled from '@emotion/styled'; -import { Form, Input, Modal, Select } from 'antd'; +import { Form, Input, Modal, Select, Collapse, Checkbox } from 'antd'; import { usePrefixedTranslation } from 'hooks'; import { LitdNode } from 'shared/types'; import { LightningNodeChannelAsset } from 'lib/lightning/types'; @@ -29,6 +29,7 @@ const Styled = { interface FormValues { node: string; invoice: string; + allowSelfPayment?: boolean; } interface Props { @@ -73,11 +74,20 @@ const PayInvoiceModal: React.FC = ({ network }) => { let amount = '0'; let assetName = 'sats'; if (assetId === 'sats') { - const res = await payInvoice({ node, invoice }); + const res = await payInvoice({ + node, + invoice, + allowSelfPayment: values.allowSelfPayment, + }); amount = format(res.amount); } else { const litdNode = node as LitdNode; - const res = await payAssetInvoice({ node: litdNode, assetId, invoice }); + const res = await payAssetInvoice({ + node: litdNode, + assetId, + invoice, + allowSelfPayment: values.allowSelfPayment, + }); amount = formatAssetAmount({ assetId, amount: res.amount }); const asset = assets.find(a => a.id === assetId) as LightningNodeChannelAsset; assetName = asset.name; @@ -114,7 +124,7 @@ const PayInvoiceModal: React.FC = ({ network }) => { layout="vertical" requiredMark={false} colon={false} - initialValues={{ node: nodeName, assetId: 'sats' }} + initialValues={{ node: nodeName, assetId: 'sats', allowSelfPayment: false }} onFinish={payAsync.execute} disabled={payAsync.loading} > @@ -156,6 +166,16 @@ const PayInvoiceModal: React.FC = ({ network }) => { > + + + + {l('allowSelfPayment')} + + + )} diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 4e1c9fa782..49aa21eff9 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -5,6 +5,7 @@ "enums.status.Stopped": "Stopped", "enums.status.Error": "Error", "cmps.forms.required": "required", + "cmps.forms.advancedOptions": "Advanced Options", "cmps.common.form.DockerCommandInput.label": "Docker Startup Command", "cmps.common.form.DockerCommandInput.help": "The docker command to execute when starting this node. If left blank, the default command will be used.", "cmps.common.form.DockerCommandInput.prefillTip": "Pre-fill with the default command", @@ -275,6 +276,7 @@ "cmps.designer.lightning.actions.PayInvoiceModal.submitError": "Unable to pay the Invoice", "cmps.designer.lightning.actions.PayInvoiceModal.successTitle": "Successfully paid the Invoice", "cmps.designer.lightning.actions.PayInvoiceModal.successDesc": "Sent {{amount}} {{assetName}} from {{nodeName}}", + "cmps.designer.lightning.actions.PayInvoiceModal.allowSelfPayment": "Allow self-payment", "cmps.designer.lightning.actions.PaymentButtons.paymentsTitle": "Payments", "cmps.designer.lightning.actions.PaymentButtons.payInvoice": "Pay Invoice", "cmps.designer.lightning.actions.PaymentButtons.createInvoice": "Create Invoice", diff --git a/src/lib/lightning/lnd/lndService.spec.ts b/src/lib/lightning/lnd/lndService.spec.ts index a312152419..d835797401 100644 --- a/src/lib/lightning/lnd/lndService.spec.ts +++ b/src/lib/lightning/lnd/lndService.spec.ts @@ -139,6 +139,34 @@ describe('LndService', () => { expect(actual.destination).toEqual('asdf'); }); + it('should pay an invoice with allowSelfPayment option', async () => { + const payResponse = { paymentPreimage: 'preimage' }; + const decodeResponse = { + paymentPreimage: 'preimage', + numSatoshis: '10000', + destination: 'asdf', + }; + lndProxyClient.payInvoice = jest.fn().mockResolvedValue(payResponse); + lndProxyClient.decodeInvoice = jest.fn().mockResolvedValue(decodeResponse); + const actual = await lndService.payInvoice( + node, + 'lnbc1invoice', + undefined, + undefined, + { allowSelfPayment: true }, + ); + expect(actual.preimage).toEqual('preimage'); + expect(actual.amount).toEqual(10000); + expect(actual.destination).toEqual('asdf'); + expect(lndProxyClient.payInvoice).toHaveBeenCalledWith( + node, + expect.objectContaining({ + paymentRequest: 'lnbc1invoice', + allowSelfPayment: true, + }), + ); + }); + it('should pay invoice with amount for a payreq without one', async () => { const payResponse = { paymentPreimage: 'preimage' }; const decodeResponse = { diff --git a/src/lib/lightning/lnd/lndService.ts b/src/lib/lightning/lnd/lndService.ts index c205f07318..3ad1bc9d85 100644 --- a/src/lib/lightning/lnd/lndService.ts +++ b/src/lib/lightning/lnd/lndService.ts @@ -8,7 +8,7 @@ import { waitFor } from 'utils/async'; import { lndProxyClient as proxy } from './'; import { mapOpenChannel, mapPendingChannel } from './mappers'; -class LndService implements LightningService { +export class LndService implements LightningService { async getInfo(node: LightningNode): Promise { const info = await proxy.getInfo(this.cast(node)); return { @@ -170,6 +170,7 @@ class LndService implements LightningService { invoice: string, amount?: number, customRecords?: PLN.CustomRecords, + advancedOptions?: PLN.SendPaymentRequestAdvancedOptions, ): Promise { let feeLimitSat = 1000; if (amount && amount > 1000) { @@ -182,6 +183,7 @@ class LndService implements LightningService { firstHopCustomRecords: customRecords, timeoutSeconds: 60, maxParts: 16, + ...advancedOptions, }; // don't set an amount if the invoice has one set already diff --git a/src/lib/lightning/types.ts b/src/lib/lightning/types.ts index 4e1b282b5d..b2a8d04837 100644 --- a/src/lib/lightning/types.ts +++ b/src/lib/lightning/types.ts @@ -3,6 +3,8 @@ * lightning implementations */ +export { LndService } from './lnd/lndService'; + export interface LightningNodeInfo { pubkey: string; alias: string; @@ -76,6 +78,10 @@ export interface LightningNodePaymentRequest { expiry: string; } +export interface SendPaymentRequestAdvancedOptions { + allowSelfPayment?: boolean; +} + export interface LightningNodeChannelEvent { type: 'Open' | 'Pending' | 'Closed' | 'Unknown'; } diff --git a/src/lib/tap/tapd/tapdService.ts b/src/lib/tap/tapd/tapdService.ts index 0de6424f90..25e6eea82a 100644 --- a/src/lib/tap/tapd/tapdService.ts +++ b/src/lib/tap/tapd/tapdService.ts @@ -170,6 +170,7 @@ class TapdService implements TapService { invoice: string, feeLimitMsat: number, peerPubkey?: string, + allowSelfPayment?: boolean, ): Promise { const req: TAP.tapchannelrpc.SendPaymentRequestPartial = { assetId: Buffer.from(assetId, 'hex').toString('base64'), @@ -177,6 +178,7 @@ class TapdService implements TapService { paymentRequest: invoice, timeoutSeconds: 60 * 60, // 1 hour feeLimitMsat, + allowSelfPayment, }, }; if (peerPubkey) { diff --git a/src/store/models/lightning.ts b/src/store/models/lightning.ts index d111186106..1dc0e5c32d 100644 --- a/src/store/models/lightning.ts +++ b/src/store/models/lightning.ts @@ -8,7 +8,6 @@ import { BLOCKS_TIL_CONFIRMED } from 'utils/constants'; import { getInvoicePayload } from 'utils/network'; import { fromSatsNumeric } from 'utils/units'; import { RootModel } from './'; -import { LightningNodeChannel } from 'lib/lightning/types'; export interface LightningNodeMapping { [key: string]: LightningNodeModel; @@ -43,6 +42,7 @@ export interface PayInvoicePayload { node: LightningNode; invoice: string; amount?: number; + allowSelfPayment?: boolean; } export interface LightningModel { @@ -267,11 +267,19 @@ const lightningModel: LightningModel = { payInvoice: thunk( async ( actions, - { node, invoice, amount }, + { node, invoice, amount, allowSelfPayment }, { injections, getStoreState, getStoreActions }, ) => { const api = injections.lightningFactory.getService(node); - const receipt = await api.payInvoice(node, invoice, amount); + + let receipt; + if (api instanceof PLN.LndService) { + receipt = await api.payInvoice(node, invoice, amount, undefined, { + allowSelfPayment, + }); + } else { + receipt = await api.payInvoice(node, invoice, amount); + } const network = getStoreState().network.networkById(node.networkId); // synchronize the chart with the new channel @@ -365,7 +373,7 @@ const lightningModel: LightningModel = { state.channelsInfo = payload; }), resetChannelsInfo: thunk(async (actions, network, { getStoreState }) => { - const channels = [] as LightningNodeChannel[]; + const channels = [] as PLN.LightningNodeChannel[]; const { getChannels } = actions; const { links } = getStoreState().designer.activeChart; @@ -438,9 +446,9 @@ const lightningModel: LightningModel = { if (!network) throw new Error('networkByIdErr'); const { createInvoice, payInvoice, getChannels } = actions; const lnNodes = network.nodes.lightning; - const channels = [] as LightningNodeChannel[]; + const channels = [] as PLN.LightningNodeChannel[]; const id2Node = {} as Record; - const id2channel = {} as Record; + const id2channel = {} as Record; await Promise.all( lnNodes.map(async node => { diff --git a/src/store/models/lit.ts b/src/store/models/lit.ts index c89119c830..4c7e59f4e5 100644 --- a/src/store/models/lit.ts +++ b/src/store/models/lit.ts @@ -37,6 +37,7 @@ export interface PayInvoicePayload { node: LitdNode; assetId: string; invoice: string; + allowSelfPayment?: boolean; } export interface LitModel { @@ -141,7 +142,7 @@ const litModel: LitModel = { payAssetInvoice: thunk( async ( actions, - { node, assetId, invoice }, + { node, assetId, invoice, allowSelfPayment }, { injections, getStoreState, getStoreActions }, ) => { const assetsInChannels = actions @@ -170,6 +171,7 @@ const litModel: LitModel = { invoice, feeLimit, peerPubkey, + allowSelfPayment, ); // synchronize the chart with the new channel diff --git a/src/types/index.ts b/src/types/index.ts index af436c53b9..08d372d33c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -185,6 +185,7 @@ export interface LightningService { invoice: string, amount?: number, customRecords?: PLN.CustomRecords, + advancedOptions?: PLN.SendPaymentRequestAdvancedOptions, ) => Promise; decodeInvoice: ( node: LightningNode, @@ -245,6 +246,7 @@ export interface TapService { invoice: string, feeLimitMsat: number, peerPubkey?: string, + allowSelfPayment?: boolean, ) => Promise; } From 937b875e5bb8deac6b4a1d69877fca3c4db44885 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Tue, 2 Dec 2025 14:16:10 +0200 Subject: [PATCH 77/77] feat: add ability to specify Price Oracle metadata when creating an invoice --- package.json | 4 +- .../actions/CreateInvoiceModal.spec.tsx | 31 ++++++++++ .../lightning/actions/CreateInvoiceModal.tsx | 44 ++++++++++++++- .../actions/PayInvoiceModal.spec.tsx | 56 +++++++++++++++++++ .../lightning/actions/PayInvoiceModal.tsx | 12 ++++ src/i18n/locales/en-US.json | 4 ++ src/lib/tap/tapd/tapdService.spec.ts | 1 + src/lib/tap/tapd/tapdService.ts | 5 ++ src/shared/lndDefaults.ts | 2 + src/shared/tapdDefaults.ts | 1 + src/store/models/lightning.ts | 12 +++- src/store/models/lit.spec.ts | 2 + src/store/models/lit.ts | 9 ++- src/types/index.ts | 3 + yarn.lock | 16 +++--- 15 files changed, 184 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 9cd292d62b..5310a85da9 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ }, "dependencies": { "@lightningpolar/litd-api": "0.15.0-alpha.rc1", - "@lightningpolar/lnd-api": "0.19.0-beta", - "@lightningpolar/tapd-api": "0.6.0-alpha.rc2", + "@lightningpolar/lnd-api": "0.20.0-beta", + "@lightningpolar/tapd-api": "0.7.0-alpha", "@types/lodash": "4.17.21", "archiver": "7.0.1", "docker-compose": "0.24.0", diff --git a/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx b/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx index 7a1939ee6b..9a212adcec 100644 --- a/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx +++ b/src/components/designer/lightning/actions/CreateInvoiceModal.spec.tsx @@ -210,9 +210,40 @@ describe('CreateInvoiceModal', () => { 200, '', 3600, + undefined, ); }); + it('should create invoice with metadata for asset invoice', async () => { + const { getByText, getByLabelText, findByText, changeSelect } = + await renderComponent(); + expect(await findByText('Node')).toBeInTheDocument(); + changeSelect('Asset to Receive', 'test asset'); + fireEvent.change(getByLabelText('Amount'), { target: { value: '10' } }); + fireEvent.click(getByText('Advanced Options')); + const metadataInput = getByLabelText('Metadata'); + expect(metadataInput).toBeInTheDocument(); + fireEvent.change(metadataInput, { target: { value: 'test metadata' } }); + fireEvent.click(getByText('Create Invoice')); + expect(await findByText('Successfully Created the Invoice')).toBeInTheDocument(); + const node = network.nodes.lightning[0]; + const tapNode = mapToTapd(node); + expect(tapServiceMock.addInvoice).toHaveBeenCalledWith( + tapNode, + 'abcd', + 10, + '', + 3600, + 'test metadata', + ); + }); + + it('should not show metadata field for Bitcoin payments', async () => { + const { queryByLabelText, findByText } = await renderComponent(); + expect(await findByText('Node')).toBeInTheDocument(); + expect(queryByLabelText('Advanced Options')).not.toBeInTheDocument(); + }); + it('should display an error when creating an asset invoice with a high balance', async () => { const { getByText, getByLabelText, findByText, changeSelect } = await renderComponent(); diff --git a/src/components/designer/lightning/actions/CreateInvoiceModal.tsx b/src/components/designer/lightning/actions/CreateInvoiceModal.tsx index 1c700326d1..b9d9d7b3bc 100644 --- a/src/components/designer/lightning/actions/CreateInvoiceModal.tsx +++ b/src/components/designer/lightning/actions/CreateInvoiceModal.tsx @@ -2,7 +2,17 @@ import React, { ReactNode, useCallback, useMemo } from 'react'; import { useAsync, useAsyncCallback } from 'react-async-hook'; import CopyToClipboard from 'react-copy-to-clipboard'; import styled from '@emotion/styled'; -import { Button, Form, InputNumber, message, Modal, Result, Select } from 'antd'; +import { + Button, + Form, + Input, + InputNumber, + message, + Modal, + Result, + Select, + Collapse, +} from 'antd'; import { usePrefixedTranslation } from 'hooks'; import { LitdNode } from 'shared/types'; import { LightningNodeChannelAsset } from 'lib/lightning/types'; @@ -32,6 +42,7 @@ interface FormValues { node: string; assetId: string; amount: number; + metadata?: string; } interface Props { @@ -88,7 +99,12 @@ const CreateInvoiceModal: React.FC = ({ network }) => { } else { const litdNode = node as LitdNode; const amount = toAssetUnits({ assetId, amount: values.amount }); - const res = await createAssetInvoice({ node: litdNode, assetId, amount }); + const res = await createAssetInvoice({ + node: litdNode, + assetId, + amount, + metadata: values.metadata, + }); invoice = res.invoice; const asset = assets.find(a => a.id === assetId) as LightningNodeChannelAsset; assetName = `${asset.name} (${format(res.sats)} sats)`; @@ -131,7 +147,12 @@ const CreateInvoiceModal: React.FC = ({ network }) => { layout="vertical" requiredMark={false} colon={false} - initialValues={{ node: nodeName, amount: 1_000_000, assetId: 'sats' }} + initialValues={{ + node: nodeName, + amount: 1_000_000, + assetId: 'sats', + metadata: '', + }} onFinish={createAsync.execute} > = ({ network }) => { style={{ width: '100%' }} /> + + {isLitd && assetId && assetId !== 'sats' && ( + + + + + + + + )} ); } else { diff --git a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx index f20abe3b7f..545f196da2 100644 --- a/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx +++ b/src/components/designer/lightning/actions/PayInvoiceModal.spec.tsx @@ -118,6 +118,9 @@ describe('PayInvoiceModal', () => { node, 'lnbc1', undefined, + undefined, + undefined, + undefined, ); const element = await findByText('Sent 1,000 sats from alice'); expect(element).toBeInTheDocument(); @@ -131,6 +134,27 @@ describe('PayInvoiceModal', () => { expect(await findByText('Unable to pay the Invoice')).toBeInTheDocument(); expect(await findByText('error-msg')).toBeInTheDocument(); }); + + it('should not show metadata field for Bitcoin payments', async () => { + const { getByText, getByLabelText, queryByLabelText, store } = + await renderComponent(); + fireEvent.change(getByLabelText('BOLT 11 Invoice'), { target: { value: 'lnbc1' } }); + fireEvent.click(getByText('Advanced Options')); + expect(queryByLabelText('Metadata')).not.toBeInTheDocument(); + fireEvent.click(getByText('Pay Invoice')); + await waitFor(() => { + expect(store.getState().modals.payInvoice.visible).toBe(false); + }); + const node = network.nodes.lightning[0]; + expect(lightningServiceMock.payInvoice).toHaveBeenCalledWith( + node, + 'lnbc1', + undefined, + undefined, + undefined, + undefined, + ); + }); }); describe('with assets', () => { @@ -202,6 +226,7 @@ describe('PayInvoiceModal', () => { 400000, '', undefined, + undefined, ); }); @@ -226,7 +251,38 @@ describe('PayInvoiceModal', () => { 400000, '', true, + undefined, ); }); + + it('should pay invoice with metadata for Taproot Assets', async () => { + const { findByText, getByText, getByLabelText, store, changeSelect } = + await renderComponent('bob'); + expect(await findByText('From Node')).toBeInTheDocument(); + fireEvent.change(getByLabelText('BOLT 11 Invoice'), { target: { value: 'lnbc1' } }); + changeSelect('Asset to Send', 'test asset'); + fireEvent.click(getByText('Advanced Options')); + const metadataInput = getByLabelText('Metadata'); + expect(metadataInput).toBeInTheDocument(); + fireEvent.change(metadataInput, { + target: { value: 'test metadata' }, + }); + fireEvent.click(getByText('Pay Invoice')); + await waitFor(() => { + expect(store.getState().modals.payInvoice.visible).toBe(false); + }); + const node = network.nodes.lightning[1]; // Changed from 0 to 1 + expect(tapServiceMock.sendPayment).toHaveBeenCalledWith( + mapToTapd(node), + 'abcd', + 'lnbc1', + 400000, + '', + false, + 'test metadata', + ); + const element = await findByText('Sent 1,000 test asset from bob'); + expect(element).toBeInTheDocument(); + }); }); }); diff --git a/src/components/designer/lightning/actions/PayInvoiceModal.tsx b/src/components/designer/lightning/actions/PayInvoiceModal.tsx index 1d11218398..4cd30c84ed 100644 --- a/src/components/designer/lightning/actions/PayInvoiceModal.tsx +++ b/src/components/designer/lightning/actions/PayInvoiceModal.tsx @@ -2,6 +2,7 @@ import React, { useMemo } from 'react'; import { useAsync, useAsyncCallback } from 'react-async-hook'; import styled from '@emotion/styled'; import { Form, Input, Modal, Select, Collapse, Checkbox } from 'antd'; +import TextArea from 'antd/lib/input/TextArea'; import { usePrefixedTranslation } from 'hooks'; import { LitdNode } from 'shared/types'; import { LightningNodeChannelAsset } from 'lib/lightning/types'; @@ -30,6 +31,7 @@ interface FormValues { node: string; invoice: string; allowSelfPayment?: boolean; + metadata?: string; } interface Props { @@ -87,6 +89,7 @@ const PayInvoiceModal: React.FC = ({ network }) => { assetId, invoice, allowSelfPayment: values.allowSelfPayment, + metadata: values.metadata, }); amount = formatAssetAmount({ assetId, amount: res.amount }); const asset = assets.find(a => a.id === assetId) as LightningNodeChannelAsset; @@ -174,6 +177,15 @@ const PayInvoiceModal: React.FC = ({ network }) => { {l('allowSelfPayment')} + {assetId !== 'sats' && ( + +