From 0ef5e07180bec5c07c7b5b313abfd1dbbfaa739f Mon Sep 17 00:00:00 2001 From: p2arthur Date: Tue, 4 Nov 2025 13:42:20 -0800 Subject: [PATCH 01/18] chore(merge-main): merge latest from main with tailwind v4 to optional sender branch --- package-lock.json | 3240 +++++++++++++++++++++++- src/features/forms/components/form.tsx | 2 +- 2 files changed, 3199 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 956305d3..b24a1a29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,6 +135,7 @@ "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" @@ -146,6 +147,7 @@ "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@actions/io": "^1.0.1" } @@ -156,6 +158,7 @@ "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" @@ -166,7 +169,8 @@ "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@adobe/css-tools": { "version": "4.4.4", @@ -1251,6 +1255,7 @@ "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=14" } @@ -1677,13 +1682,13 @@ "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz", - "integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^15.0.1" + "@octokit/types": "^16.0.0" }, "engines": { "node": ">= 20" @@ -3497,6 +3502,7 @@ "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "compare-func": "^2.0.0" }, @@ -3510,6 +3516,7 @@ "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "meow": "^13.0.0" }, @@ -3526,6 +3533,7 @@ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -3588,14 +3596,14 @@ } }, "node_modules/@semantic-release/github": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.6.tgz", - "integrity": "sha512-ctDzdSMrT3H+pwKBPdyCPty6Y47X8dSrjd3aPZ5KKIKKWTwZBE9De8GtsH3TyAlw3Uyo2stegMx6rJMXKpJwJA==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-12.0.1.tgz", + "integrity": "sha512-BSC7Ko6aRPnH8ttVBpd3gC98LTiyPdmrmX4qHilLw5EZqVrXrXwcKp/JKUC5hgm0XpJACR3nPjgbfOjTJ75PIA==", "dev": true, "license": "MIT", "dependencies": { "@octokit/core": "^7.0.0", - "@octokit/plugin-paginate-rest": "^13.0.0", + "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", @@ -3612,7 +3620,7 @@ "url-join": "^5.0.0" }, "engines": { - "node": ">=20.8.1" + "node": "^22.14.0 || >= 24.10.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" @@ -3638,6 +3646,21 @@ "clean-stack": "^5.2.0", "indent-string": "^5.0.0" }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, "engines": { "node": ">=18" }, @@ -3667,6 +3690,7 @@ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3680,6 +3704,7 @@ "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3709,6 +3734,7 @@ "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -3980,6 +4006,7 @@ "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "compare-func": "^2.0.0" }, @@ -3993,6 +4020,7 @@ "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "meow": "^13.0.0" }, @@ -4022,6 +4050,7 @@ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -5874,6 +5903,7 @@ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 14" } @@ -5949,6 +5979,7 @@ "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "environment": "^1.0.0" }, @@ -7975,6 +8006,7 @@ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8004,6 +8036,7 @@ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mimic-fn": "^4.0.0" }, @@ -8033,6 +8066,7 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=14" }, @@ -9059,6 +9093,20 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -9159,6 +9207,7 @@ "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "through2": "~2.0.0" } @@ -9169,6 +9218,7 @@ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -11096,6 +11146,7 @@ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -11337,6 +11388,7 @@ "integrity": "sha512-T9BPOmEOhp6SmV25SwLVcHK4E6JyG/coH3C6F1NjNXSziv/fd4GmsqMk8YR6qpPOswfaOCApSNkZv6fxoaYFcQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-event": "^6.0.0", "type-fest": "^4.6.0", @@ -11355,6 +11407,7 @@ "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-timeout": "^6.1.2" }, @@ -11371,6 +11424,7 @@ "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=14.16" }, @@ -11689,9 +11743,9 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.12.0.tgz", - "integrity": "sha512-jzf2eVnd8+iWXN74dccLrHUw3i3hFVvNVQRWS4vBl2KxaUt7Tdur0Eyda/DODGFkZDu2P5MXaeLe/9Qx8PZkrg==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.6.tgz", + "integrity": "sha512-MCYMykvmiYScyUm7I6y0VCxpNq1rgd5v7kG8ks5dKtvmxRUUPjribX6mUoUNBbM5/3PhUyoelEWiKXGOz84c+w==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -16774,17 +16828,17 @@ } }, "node_modules/semantic-release": { - "version": "24.2.9", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz", - "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-25.0.1.tgz", + "integrity": "sha512-0OCYLm0AfVilNGukM+w0C4aptITfuW1Mhvmz8LQliLeYbPOTFRCIJzoltWWx/F5zVFe6np9eNatBUHdAvMFeZg==", "dev": true, "license": "MIT", "dependencies": { - "@semantic-release/commit-analyzer": "^13.0.0-beta.1", + "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/error": "^4.0.0", - "@semantic-release/github": "^11.0.0", - "@semantic-release/npm": "^12.0.2", - "@semantic-release/release-notes-generator": "^14.0.0-beta.1", + "@semantic-release/github": "^12.0.0", + "@semantic-release/npm": "^13.1.1", + "@semantic-release/release-notes-generator": "^14.1.0", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", @@ -16795,7 +16849,7 @@ "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^4.0.0", - "hosted-git-info": "^8.0.0", + "hosted-git-info": "^9.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "marked": "^15.0.0", @@ -16808,26 +16862,23 @@ "semver": "^7.3.2", "semver-diff": "^5.0.0", "signale": "^1.2.1", - "yargs": "^17.5.1" + "yargs": "^18.0.0" }, "bin": { "semantic-release": "bin/semantic-release.js" }, "engines": { - "node": ">=20.8.1" + "node": "^22.14.0 || >= 24.10.0" } }, "node_modules/semantic-release-export-data": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/semantic-release-export-data/-/semantic-release-export-data-1.0.1.tgz", - "integrity": "sha512-6vlgrrzzcMi/REhQd65Bh4dfSKmgwXOJ/Q2RVlT9WsU4Ya1T2qGpkSrMfG/n6oFRrqBdbDlyZgxNd94ziW+vSg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/semantic-release-export-data/-/semantic-release-export-data-1.2.0.tgz", + "integrity": "sha512-/9+yQWFieiN0KB7YA0TTCXHml7d2tlNLkprLjUOKf8XDQlJ6ZK9gkw0dJJ/8/kBzeuUPq8aZR2n0rYmuYCz7Xg==", "dev": true, "license": "MIT", - "dependencies": { - "@actions/core": "^1.10.0" - }, "peerDependencies": { - "semantic-release": ">=18" + "semantic-release": ">=20" } }, "node_modules/semantic-release/node_modules/@semantic-release/error": { @@ -16836,16 +16887,49 @@ "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" } }, + "node_modules/semantic-release/node_modules/@semantic-release/npm": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-13.1.1.tgz", + "integrity": "sha512-c4tlp3STYaTYORmMcLjiTaI8SLoxJ0Uf7IXkem8EyihuOM624wnaGuH4OuY2HHcsHDerNAQNzZ8VO6d4PMHSzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@actions/core": "^1.11.1", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "env-ci": "^11.2.0", + "execa": "^9.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^11.6.2", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, "node_modules/semantic-release/node_modules/aggregate-error": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" @@ -16857,12 +16941,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/semantic-release/node_modules/clean-stack": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "escape-string-regexp": "5.0.0" }, @@ -16873,12 +16986,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/semantic-release/node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -16900,12 +17029,21 @@ } } }, + "node_modules/semantic-release/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/semantic-release/node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -16919,6 +17057,7 @@ "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", @@ -16946,6 +17085,7 @@ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" @@ -16958,16 +17098,17 @@ } }, "node_modules/semantic-release/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { - "lru-cache": "^10.0.1" + "lru-cache": "^11.1.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/semantic-release/node_modules/human-signals": { @@ -16976,6 +17117,7 @@ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18.0" } @@ -16986,6 +17128,7 @@ "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -16999,6 +17142,7 @@ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -17006,29 +17150,2949 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/semantic-release/node_modules/npm": { + "version": "11.6.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.6.2.tgz", + "integrity": "sha512-7iKzNfy8lWYs3zq4oFPa8EXZz5xt9gQNKJZau3B1ErLBb6bF7sBJ00x09485DOvRT2l5Gerbl3VlZNT57MxJVA==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which" + ], + "dev": true, + "license": "Artistic-2.0", + "peer": true, + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^9.1.6", + "@npmcli/config": "^10.4.2", + "@npmcli/fs": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.1", + "@npmcli/promise-spawn": "^8.0.3", + "@npmcli/redact": "^3.2.2", + "@npmcli/run-script": "^10.0.0", + "@sigstore/tuf": "^4.0.0", + "abbrev": "^3.0.1", + "archy": "~1.0.0", + "cacache": "^20.0.1", + "chalk": "^5.6.2", + "ci-info": "^4.3.1", + "cli-columns": "^4.0.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^11.0.3", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^9.0.2", + "ini": "^5.0.0", + "init-package-json": "^8.2.2", + "is-cidr": "^6.0.1", + "json-parse-even-better-errors": "^4.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.0.9", + "libnpmexec": "^10.1.8", + "libnpmfund": "^7.0.9", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.0.9", + "libnpmpublish": "^11.1.2", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.2", + "make-fetch-happen": "^15.0.2", + "minimatch": "^10.0.3", + "minipass": "^7.1.1", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^11.4.2", + "nopt": "^8.1.0", + "npm-audit-report": "^6.0.0", + "npm-install-checks": "^7.1.2", + "npm-package-arg": "^13.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-profile": "^12.0.0", + "npm-registry-fetch": "^19.0.0", + "npm-user-validate": "^3.0.0", + "p-map": "^7.0.3", + "pacote": "^21.0.3", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^4.1.0", + "semver": "^7.7.3", + "spdx-expression-parse": "^4.0.0", + "ssri": "^12.0.0", + "supports-color": "^10.2.2", + "tar": "^7.5.1", + "text-table": "~0.2.0", + "tiny-relative-date": "^2.0.2", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^6.0.2", + "which": "^5.0.0" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/semantic-release/node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/agent": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/arborist": { + "version": "9.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^4.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^4.0.0", + "@npmcli/redact": "^3.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^5.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^9.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^8.0.0", + "npm-install-checks": "^7.1.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "proggy": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^12.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/config": { + "version": "10.4.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^5.0.0", + "nopt": "^8.1.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/fs": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/git": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^11.0.3", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "9.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^4.0.0", + "pacote": "^21.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/package-json": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^11.0.3", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "8.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/query": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/redact": { + "version": "3.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "node-gyp": "^11.0.0", + "proc-log": "^5.0.0", + "which": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/bundle": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/core": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.5.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/sign": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.2", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/tuf": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/models": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/abbrev": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/agent-base": { + "version": "7.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/aproba": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/bin-links": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cmd-shim": "^7.0.0", + "npm-normalize-package-bin": "^4.0.0", + "proc-log": "^5.0.0", + "read-cmd-shim": "^5.0.0", + "write-file-atomic": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cacache": { + "version": "20.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^11.0.3", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/chalk": { + "version": "5.6.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ci-info": { + "version": "4.3.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cidr-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "ip-regex": "5.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cmd-shim": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/debug": { + "version": "4.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/diff": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/foreground-child": { + "version": "3.3.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/glob": { + "version": "11.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/hosted-git-info": { + "version": "9.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ignore-walk": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ini": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/init-package-json": { + "version": "8.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^2.0.0", + "read": "^4.0.0", + "semver": "^7.7.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^6.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ip-address": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/is-cidr": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "cidr-regex": "5.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/jackspeak": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmaccess": { + "version": "10.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmdiff": { + "version": "8.0.9", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^9.1.6", + "@npmcli/installed-package-contents": "^3.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmexec": { + "version": "10.1.8", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^9.1.6", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "read": "^4.0.0", + "semver": "^7.3.7", + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmfund": { + "version": "7.0.9", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^9.1.6" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmorg": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmpack": { + "version": "9.0.9", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/arborist": "^9.1.6", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmpublish": { + "version": "11.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.7", + "sigstore": "^4.0.0", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmsearch": { + "version": "9.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmteam": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/libnpmversion": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/lru-cache": { + "version": "11.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/make-fetch-happen": { + "version": "15.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minimatch": { + "version": "10.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-fetch": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/mute-stream": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp": { + "version": "11.4.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/agent": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/cacache": { + "version": "19.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/glob": { + "version": "10.4.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/jackspeak": { + "version": "3.4.3", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "14.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/nopt": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-audit-report": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-bundled": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-install-checks": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-package-arg": { + "version": "13.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-packlist": { + "version": "10.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-pick-manifest": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-profile": { + "version": "12.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "npm-registry-fetch": "^19.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-registry-fetch": { + "version": "19.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/redact": "^3.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/npm-user-validate": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/p-map": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/package-json-from-dist": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/pacote": { + "version": "21.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^4.0.0", + "ssri": "^12.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/parse-conflict-json": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/path-scurry": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/proc-log": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/proggy": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/promzard": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "read": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "peer": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/read": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "mute-stream": "^2.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/read-cmd-shim": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/semver": { + "version": "7.7.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/sigstore": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.0.0", + "@sigstore/tuf": "^4.0.0", + "@sigstore/verify": "^3.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/socks": { + "version": "2.8.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.22", + "dev": true, + "inBundle": true, + "license": "CC0-1.0", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/ssri": { + "version": "12.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/supports-color": { + "version": "10.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tar": { + "version": "7.5.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.15", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/tuf-js": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@tufjs/models": "4.0.0", + "debug": "^4.4.1", + "make-fetch-happen": "^15.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/unique-filename": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" + "unique-slug": "^5.0.0" }, "engines": { - "node": ">=18" + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/unique-slug": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-name": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/which": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true + }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/write-file-atomic": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "peer": true + }, "node_modules/semantic-release/node_modules/p-reduce": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -17042,6 +20106,7 @@ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -17055,6 +20120,7 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=14" }, @@ -17062,12 +20128,49 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/semantic-release/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/semantic-release/node_modules/strip-final-newline": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -17081,6 +20184,7 @@ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -17088,6 +20192,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/semantic-release/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -18460,6 +21613,7 @@ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -18676,6 +21830,7 @@ "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -18945,9 +22100,9 @@ } }, "node_modules/vite": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.0.tgz", - "integrity": "sha512-C/Naxf8H0pBx1PA4BdpT+c/5wdqI9ILMdwjSMILw7tVIh3JsxzZqdeTLmmdaoh5MYUEOyBnM9K3o0DzoZ/fe+w==", + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", "dependencies": { @@ -19194,7 +22349,8 @@ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", "dev": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/whatwg-mimetype": { "version": "3.0.0", diff --git a/src/features/forms/components/form.tsx b/src/features/forms/components/form.tsx index 952b468b..25100ee9 100644 --- a/src/features/forms/components/form.tsx +++ b/src/features/forms/components/form.tsx @@ -16,7 +16,7 @@ export interface FormProps> { children: | ReactNode | ((helper: FormFieldHelper, handleSubmit: (e?: React.FormEvent) => Promise) => ReactNode) - formAction: ReactNode | ((ctx: UseFormReturn, resetLocalState: () => void) => ReactNode) + formAction: ReactNode | ((ctx: UseFormReturn, resetLocalState: () => void) => ReactNode) onSuccess?: (data: TData) => void onSubmit: (values: z.infer>) => Promise | TData resetOnSuccess?: boolean From 2630b66b90b4ece5f42276b0d9394c69c7974d70 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Fri, 7 Nov 2025 01:44:20 -0800 Subject: [PATCH 02/18] feat(optional_sender): Add optional sender at latest squashed to solve unsigned commits --- .../components/transaction-sender-link.tsx | 38 +++ .../forms/components/address-form-item.tsx | 14 +- .../account-close-transaction-builder.tsx | 20 +- .../app-call-transaction-builder.tsx | 13 +- ...application-create-transaction-builder.tsx | 13 +- ...application-update-transaction-builder.tsx | 13 +- .../asset-clawback-transaction-builder.tsx | 13 +- .../asset-create-transaction-builder.tsx | 21 +- .../asset-destroy-transaction-builder.tsx | 13 +- .../asset-freeze-transaction-builder.tsx | 13 +- .../asset-opt-in-transaction-builder.tsx | 13 +- .../asset-opt-out-transaction-builder.tsx | 13 +- .../asset-reconfigure-transaction-builder.tsx | 22 +- .../asset-transfer-transaction-builder.tsx | 13 +- .../key-registration-transaction-builder.tsx | 13 +- .../method-call-transaction-builder.tsx | 13 +- .../payment-transaction-builder.tsx | 13 +- .../components/transactions-builder.tsx | 14 +- .../components/transactions-table.tsx | 1 + .../transaction-wizard/data/common.ts | 7 + .../mappers/as-address-or-nfd.ts | 19 +- .../mappers/as-algosdk-transactions.ts | 36 +-- .../mappers/as-description-list-items.tsx | 19 +- .../transaction-wizard/models/index.ts | 8 +- .../transaction-wizard-page.test.tsx | 234 ++++++++++++++++++ .../transaction-wizard-page.tsx | 2 + .../utils/resolve-sender-address.ts | 48 ++++ .../transactions-url-search-params.test.tsx | 113 ++------- .../transform-search-params-transactions.ts | 60 ++--- 29 files changed, 556 insertions(+), 276 deletions(-) create mode 100644 src/features/accounts/components/transaction-sender-link.tsx create mode 100644 src/features/transaction-wizard/utils/resolve-sender-address.ts diff --git a/src/features/accounts/components/transaction-sender-link.tsx b/src/features/accounts/components/transaction-sender-link.tsx new file mode 100644 index 00000000..02042347 --- /dev/null +++ b/src/features/accounts/components/transaction-sender-link.tsx @@ -0,0 +1,38 @@ +import { Nfd } from '@/features/nfd/data/types' + +import { PropsWithChildren } from 'react' +import { AddressOrNfdLink } from './address-or-nfd-link' +import { Address } from '../data/types' +import { cn } from '@/features/common/utils' + +export type Props = PropsWithChildren<{ + address: Address + short?: boolean + className?: string + showCopyButton?: boolean + showQRButton?: boolean + nfd?: Nfd + autoPopulated?: boolean +}> + +export default function TransactionSenderLink({ address, short, showCopyButton, showQRButton, nfd, autoPopulated }: Props) { + return ( +
+ + + {autoPopulated && ( + + ? +
auto populated
+
+ )} +
+ ) +} diff --git a/src/features/forms/components/address-form-item.tsx b/src/features/forms/components/address-form-item.tsx index 455cfab1..4da1eca0 100644 --- a/src/features/forms/components/address-form-item.tsx +++ b/src/features/forms/components/address-form-item.tsx @@ -1,7 +1,7 @@ import { FieldPath, useFormContext } from 'react-hook-form' import { FormItemProps } from '@/features/forms/components/form-item' import { TextFormItem } from './text-form-item' -import { addressFieldSchema, optionalAddressFieldSchema } from '@/features/transaction-wizard/data/common' +import { addressFieldSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' import { useDebounce } from 'use-debounce' import { isNfd, useLoadableForwardLookupNfdResult } from '@/features/nfd/data' import { useCallback, useEffect } from 'react' @@ -11,6 +11,7 @@ import { z } from 'zod' export type AddressOrNfdFieldSchema = z.infer export type OptionalAddressOrNfdFieldSchema = z.infer +export type OptionalSenderFieldSchema = z.infer export interface AddressFieldProps = Record> extends Omit, 'children'> { @@ -41,9 +42,14 @@ function ResolveNfdAddress({ nfd, onNfdResolved }: ResolveNfdAddressProps) { } export function AddressFormItem({ field, resolvedAddressField, label, ...props }: AddressFormItemProps) { - const { watch, setValue } = useFormContext() - const value = watch(field) - const resolvedAddress = watch(resolvedAddressField) + const { watch, setValue } = useFormContext() + const rawValue = watch(field) + + //type guard + const value = typeof rawValue === 'string' ? rawValue : '' + + const rawResolved = watch(resolvedAddressField) + const resolvedAddress = typeof rawResolved === 'string' ? rawResolved : '' const setAddress = useCallback((address: string) => setValue(resolvedAddressField, address), [resolvedAddressField, setValue]) useEffect(() => { diff --git a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx index 1410f5b4..1f62a8b4 100644 --- a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx @@ -1,5 +1,10 @@ import { numberSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, optionalAddressFieldSchema, senderFieldSchema } from '../data/common' +import { + addressFieldSchema, + commonSchema, + optionalAddressFieldSchema, + optionalSenderFieldShape, +} from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -15,8 +20,9 @@ import { TransactionBuilderMode } from '../data' import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asOptionalAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const senderLabel = 'Sender' const receiverLabel = 'Receiver' @@ -25,7 +31,7 @@ const closeRemainderToLabel = 'Close remainder to' const formSchema = z .object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, closeRemainderTo: addressFieldSchema, receiver: optionalAddressFieldSchema, amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0).optional()), @@ -63,9 +69,9 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAccoun onSubmit({ id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AccountClose, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), closeRemainderTo: data.closeRemainderTo, - receiver: asOptionalAddressOrNfd(data.receiver), + receiver: asAddressOrNfd(data.receiver.value!), amount: data.amount, fee: data.fee, validRounds: data.validRounds, @@ -77,7 +83,7 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAccoun const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), closeRemainderTo: transaction.closeRemainderTo, receiver: transaction.receiver, amount: transaction.amount, @@ -114,7 +120,7 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAccoun {helper.addressField({ field: 'sender', label: senderLabel, - helpText: 'Account to be closed. Sends the transaction and pays the fee', + helpText: 'Account to be closed. Sends the transaction and pays the fee - optional for simulating ', placeholder: ZERO_ADDRESS, })} {helper.addressField({ diff --git a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx index b44edf34..1d8aa446 100644 --- a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx @@ -1,6 +1,6 @@ import algosdk from 'algosdk' import { bigIntSchema, numberSchema } from '@/features/forms/data/common' -import { senderFieldSchema, commonSchema, onCompleteFieldSchema, onCompleteOptions } from '@/features/transaction-wizard/data/common' +import { commonSchema, onCompleteFieldSchema, onCompleteOptions, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' import { Form } from '@/features/forms/components/form' @@ -14,12 +14,13 @@ import { BuildAppCallTransactionResult, BuildableTransactionType } from '../mode import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, ...onCompleteFieldSchema, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), extraProgramPages: numberSchema(z.number().min(0).max(3).optional()), @@ -47,7 +48,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AppCall, applicationId: BigInt(values.applicationId), - sender: values.sender, + sender: await resolveSenderAddress(values.sender!), onComplete: Number(values.onComplete), extraProgramPages: values.extraProgramPages, fee: values.fee, @@ -63,7 +64,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de if (mode === TransactionBuilderMode.Edit && transaction) { return { applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), onComplete: transaction.onComplete.toString(), extraProgramPages: transaction.extraProgramPages, fee: transaction.fee, @@ -117,7 +118,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to call from. Sends the transaction and pays the fee', + helpText: 'Account to call from. Sends the transaction and pays the fee - optional for simulating', })} {defaultValues.applicationId === 0n && helper.numberField({ diff --git a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx index 575175af..3636405f 100644 --- a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx @@ -1,10 +1,10 @@ import algosdk from 'algosdk' import { numberSchema } from '@/features/forms/data/common' import { - senderFieldSchema, commonSchema, onCompleteOptionsForAppCreate, onCompleteForAppCreateFieldSchema, + optionalSenderFieldShape, } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' @@ -19,12 +19,13 @@ import { BuildApplicationCreateTransactionResult, BuildableTransactionType } fro import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, ...onCompleteForAppCreateFieldSchema, approvalProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), clearStateProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), @@ -57,7 +58,7 @@ export function ApplicationCreateTransactionBuilder({ mode, transaction, activeA type: BuildableTransactionType.ApplicationCreate, approvalProgram: values.approvalProgram, clearStateProgram: values.clearStateProgram, - sender: values.sender, + sender: await resolveSenderAddress(values.sender!), onComplete: Number(values.onComplete), extraProgramPages: values.extraProgramPages, globalInts: values.globalInts, @@ -78,7 +79,7 @@ export function ApplicationCreateTransactionBuilder({ mode, transaction, activeA return { approvalProgram: transaction.approvalProgram, clearStateProgram: transaction.clearStateProgram, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), onComplete: transaction.onComplete.toString(), extraProgramPages: transaction.extraProgramPages, globalInts: transaction.globalInts, @@ -140,7 +141,7 @@ export function ApplicationCreateTransactionBuilder({ mode, transaction, activeA {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to create from. Sends the transaction and pays the fee', + helpText: 'Account to create from. Sends the transaction and pays the fee - optional for simulating', })} {helper.numberField({ field: 'globalInts', diff --git a/src/features/transaction-wizard/components/application-update-transaction-builder.tsx b/src/features/transaction-wizard/components/application-update-transaction-builder.tsx index 89d34e85..21f7c364 100644 --- a/src/features/transaction-wizard/components/application-update-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/application-update-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { senderFieldSchema, commonSchema } from '@/features/transaction-wizard/data/common' +import { commonSchema, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' import { Form } from '@/features/forms/components/form' @@ -13,12 +13,13 @@ import { BuildApplicationUpdateTransactionResult, BuildableTransactionType } fro import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), approvalProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), clearStateProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), @@ -47,7 +48,7 @@ export function ApplicationUpdateTransactionBuilder({ mode, transaction, activeA applicationId: BigInt(values.applicationId), approvalProgram: values.approvalProgram, clearStateProgram: values.clearStateProgram, - sender: values.sender, + sender: await resolveSenderAddress(values.sender), fee: values.fee, validRounds: values.validRounds, args: values.args.map((arg) => arg.value), @@ -63,7 +64,7 @@ export function ApplicationUpdateTransactionBuilder({ mode, transaction, activeA applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, approvalProgram: transaction.approvalProgram, clearStateProgram: transaction.clearStateProgram, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, @@ -116,7 +117,7 @@ export function ApplicationUpdateTransactionBuilder({ mode, transaction, activeA {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to update from. Sends the transaction and pays the fee', + helpText: 'Account to update from. Sends the transaction and pays the fee - optional for simulating', })} {helper.arrayField({ field: 'args', diff --git a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx index f8f6c044..23ffdf8d 100644 --- a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, decimalSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, receiverFieldSchema, senderFieldSchema } from '../data/common' +import { addressFieldSchema, commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,14 +21,15 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import resolveSenderAddress from '../utils/resolve-sender-address' const clawbackTargetLabel = 'Clawback target' export const assetClawbackFormSchema = z .object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, ...receiverFieldSchema, clawbackTarget: addressFieldSchema, asset: z @@ -83,7 +84,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'The clawback account of the asset. Sends the transaction and pays the fee', + helpText: 'The clawback account of the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -186,7 +187,7 @@ export function AssetClawbackTransactionBuilder({ mode, transaction, onSubmit, o id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetClawback, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), receiver: data.receiver, clawbackTarget: data.clawbackTarget, amount: data.amount!, @@ -201,7 +202,7 @@ export function AssetClawbackTransactionBuilder({ mode, transaction, onSubmit, o if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), receiver: transaction.receiver, clawbackTarget: transaction.clawbackTarget, amount: transaction.amount, diff --git a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx index b41f01ea..d8f43542 100644 --- a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, numberSchema } from '@/features/forms/data/common' -import { commonSchema, optionalAddressFieldSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -15,12 +15,13 @@ import { FormFieldHelper } from '@/features/forms/components/form-field-helper' import { ZERO_ADDRESS } from '@/features/common/constants' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asOptionalAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetCreateFormSchema = z.object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, total: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).gt(BigInt(0), 'Must be greater than 0')), decimals: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0).max(19)), assetName: zfd.text(z.string().optional()), @@ -66,7 +67,7 @@ function FormFields({ helper }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Creator', - helpText: 'Account that creates the asset. Sends the transaction and pays the fee', + helpText: 'Account that creates the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -133,11 +134,11 @@ export function AssetCreateTransactionBuilder({ mode, transaction, activeAccount unitName: data.unitName, total: data.total, decimals: data.decimals, - sender: data.sender, - manager: asOptionalAddressOrNfd(data.manager), - reserve: asOptionalAddressOrNfd(data.reserve), - freeze: asOptionalAddressOrNfd(data.freeze), - clawback: asOptionalAddressOrNfd(data.clawback), + sender: await resolveSenderAddress(data.sender), + manager: asAddressOrNfd(data.manager.value!), + reserve: asAddressOrNfd(data.reserve.value!), + freeze: asAddressOrNfd(data.freeze.value!), + clawback: asAddressOrNfd(data.clawback.value!), defaultFrozen: data.defaultFrozen ?? false, url: data.url, metadataHash: data.metadataHash, @@ -155,7 +156,7 @@ export function AssetCreateTransactionBuilder({ mode, transaction, activeAccount unitName: transaction.unitName, total: transaction.total, decimals: transaction.decimals, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), manager: transaction.manager, reserve: transaction.reserve, freeze: transaction.freeze, diff --git a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx index 73446743..594bbb3c 100644 --- a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -24,11 +24,12 @@ import { ellipseAddress } from '@/utils/ellipse-address' import { cn } from '@/features/common/utils' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetDestroyFormSchema = z.object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -81,7 +82,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'The current asset manager address. Sends the transaction and pays the fee', + helpText: 'The current asset manager address. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} @@ -165,7 +166,7 @@ export function AssetDestroyTransactionBuilder({ mode, transaction, onSubmit, on id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetDestroy, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), fee: data.fee, validRounds: data.validRounds, note: data.note, @@ -177,7 +178,7 @@ export function AssetDestroyTransactionBuilder({ mode, transaction, onSubmit, on if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, diff --git a/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx index 545edefb..da7c8852 100644 --- a/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, senderFieldSchema } from '../data/common' +import { addressFieldSchema, commonSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -22,12 +22,13 @@ import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' import { freezeAssetLabel, unfreezeAssetLabel } from '../mappers' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetFreezeFormSchema = z .object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, freezeTarget: addressFieldSchema, frozen: z.union([z.string(), z.boolean()]), asset: z @@ -86,7 +87,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'The freeze account of the asset. Sends the transaction and pays the fee', + helpText: 'The freeze account of the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -182,7 +183,7 @@ export function AssetFreezeTransactionBuilder({ mode, transaction, onSubmit, onC id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetFreeze, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), freezeTarget: data.freezeTarget, frozen: data.frozen === 'true' ? true : false, fee: data.fee, @@ -196,7 +197,7 @@ export function AssetFreezeTransactionBuilder({ mode, transaction, onSubmit, onC if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), freezeTarget: transaction.freezeTarget, frozen: transaction.frozen ? 'true' : 'false', fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx index bb176d04..7712aefc 100644 --- a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,12 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetOptInFormSchema = z.object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -62,7 +63,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to opt in to the asset. Sends the transaction and pays the fee', + helpText: 'Account to opt in to the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} @@ -143,7 +144,7 @@ export function AssetOptInTransactionBuilder({ mode, transaction, activeAccount, id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetOptIn, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), fee: data.fee, validRounds: data.validRounds, note: data.note, @@ -155,7 +156,7 @@ export function AssetOptInTransactionBuilder({ mode, transaction, activeAccount, if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, diff --git a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx index 0157f62e..19ef4702 100644 --- a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, senderFieldSchema } from '../data/common' +import { addressFieldSchema, commonSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,12 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetOptOutFormSchema = z.object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, closeRemainderTo: addressFieldSchema, asset: z .object({ @@ -63,7 +64,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to opt out of the asset. Sends the transaction and pays the fee', + helpText: 'Account to opt out of the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -150,7 +151,7 @@ export function AssetOptOutTransactionBuilder({ mode, transaction, activeAccount id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetOptOut, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), closeRemainderTo: data.closeRemainderTo, fee: data.fee, validRounds: data.validRounds, @@ -163,7 +164,7 @@ export function AssetOptOutTransactionBuilder({ mode, transaction, activeAccount if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), closeRemainderTo: transaction.closeRemainderTo, fee: transaction.fee, validRounds: transaction.validRounds, diff --git a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx index 6c192e58..efaec0dc 100644 --- a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, optionalAddressFieldSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,12 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asOptionalAddressOrNfd, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' +import resolveSenderAddress from '../utils/resolve-sender-address' export const assetReconfigureFormSchema = z .object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -82,7 +83,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'The manager account of the asset. Sends the transaction and pays the fee', + helpText: 'The manager account of the asset. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -215,11 +216,12 @@ export function AssetReconfigureTransactionBuilder({ mode, transaction, onSubmit id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetReconfigure, asset: data.asset, - sender: data.sender, - manager: asOptionalAddressOrNfd(data.manager), - reserve: asOptionalAddressOrNfd(data.reserve), - freeze: asOptionalAddressOrNfd(data.freeze), - clawback: asOptionalAddressOrNfd(data.clawback), + + sender: await resolveSenderAddress(data.sender), + manager: asAddressOrNfd(data.manager.value!), + reserve: asAddressOrNfd(data.reserve.value!), + freeze: asAddressOrNfd(data.freeze.value!), + clawback: asAddressOrNfd(data.clawback.value!), fee: data.fee, validRounds: data.validRounds, note: data.note, @@ -231,7 +233,7 @@ export function AssetReconfigureTransactionBuilder({ mode, transaction, onSubmit if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), manager: transaction.manager, reserve: transaction.reserve, freeze: transaction.freeze, diff --git a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx index e45e6c57..f66ca996 100644 --- a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, decimalSchema } from '@/features/forms/data/common' -import { commonSchema, receiverFieldSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,14 +21,15 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const receiverLabel = 'Receiver' export const assetTransferFormSchema = z.object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, ...receiverFieldSchema, asset: z .object({ @@ -67,7 +68,7 @@ function FormFields({ helper, asset }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to transfer from. Sends the transaction and pays the fee', + helpText: 'Account to transfer from. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ @@ -161,7 +162,7 @@ export function AssetTransferTransactionBuilder({ mode, transaction, activeAccou id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AssetTransfer, asset: data.asset, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), receiver: data.receiver, amount: data.amount!, fee: data.fee, @@ -175,7 +176,7 @@ export function AssetTransferTransactionBuilder({ mode, transaction, activeAccou if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), receiver: transaction.receiver, amount: transaction.amount, fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx b/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx index 1128e1ce..88bbd021 100644 --- a/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx @@ -1,4 +1,4 @@ -import { commonSchema, requiredMessage, senderFieldSchema } from '../data/common' +import { commonSchema, optionalSenderFieldShape, requiredMessage } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -17,13 +17,14 @@ import { FormFieldHelper } from '@/features/forms/components/form-field-helper' import { useFormContext } from 'react-hook-form' import { bigIntSchema } from '@/features/forms/data/common' import { offlineKeyRegistrationLabel, onlineKeyRegistrationLabel } from '../mappers' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' export const keyRegistrationFormSchema = z .object({ ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, online: z.string(), voteKey: z.string().optional(), selectionKey: z.string().optional(), @@ -115,7 +116,7 @@ function FormFields({ helper }: FormFieldsProps) { {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to perform the key registration. Sends the transaction and pays the fee', + helpText: 'Account to perform the key registration. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.radioGroupField({ @@ -184,7 +185,7 @@ export function KeyRegistrationTransactionBuilder({ mode, transaction, activeAcc onSubmit({ id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.KeyRegistration, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), online: data.online === 'true' ? true : false, voteKey: data.voteKey, selectionKey: data.selectionKey, @@ -202,7 +203,7 @@ export function KeyRegistrationTransactionBuilder({ mode, transaction, activeAcc const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), online: transaction.online ? 'true' : 'false', voteKey: transaction.voteKey, selectionKey: transaction.selectionKey, diff --git a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx index 2e48939d..012dd33d 100644 --- a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx @@ -4,7 +4,7 @@ import { commonSchema, onCompleteFieldSchema, onCompleteOptions as _onCompleteOptions, - senderFieldSchema, + optionalSenderFieldShape, } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' @@ -36,13 +36,14 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/features/common/compo import { Info } from 'lucide-react' import { ApplicationId } from '@/features/applications/data/types' import { MethodDefinition } from '@/features/applications/models' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import { AbiFormItemValue } from '@/features/abi-methods/models' +import resolveSenderAddress from '../utils/resolve-sender-address' const appCallFormSchema = { ...commonSchema, - ...senderFieldSchema, + ...optionalSenderFieldShape, ...onCompleteFieldSchema, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), methodName: zfd.text(), @@ -156,7 +157,7 @@ export function MethodCallTransactionBuilder({ applicationId: BigInt(values.applicationId), methodDefinition: methodDefinition, onComplete: Number(values.onComplete), - sender: values.sender, + sender: await resolveSenderAddress(values.sender!), extraProgramPages: values.extraProgramPages, appSpec: appSpec!, methodArgs: methodArgs, @@ -187,7 +188,7 @@ export function MethodCallTransactionBuilder({ ) return { applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), onComplete: transaction.onComplete.toString(), methodName: transaction.methodDefinition.name, extraProgramPages: transaction.extraProgramPages, @@ -388,7 +389,7 @@ function FormInner({ helper, onAppIdChanged, onMethodNameChanged, methodDefiniti {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to call from. Sends the transaction and pays the fee', + helpText: 'Account to call from. Sends the transaction and pays the fee - optional for simulating', })} {appId === 0n && helper.numberField({ diff --git a/src/features/transaction-wizard/components/payment-transaction-builder.tsx b/src/features/transaction-wizard/components/payment-transaction-builder.tsx index a757c2e3..dd9c5e72 100644 --- a/src/features/transaction-wizard/components/payment-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/payment-transaction-builder.tsx @@ -1,5 +1,5 @@ import { numberSchema } from '@/features/forms/data/common' -import { commonSchema, receiverFieldSchema, senderFieldSchema } from '../data/common' +import { commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -15,14 +15,15 @@ import { TransactionBuilderMode } from '../data' import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' +import resolveSenderAddress from '../utils/resolve-sender-address' const receiverLabel = 'Receiver' export const paymentFormSchema = z.object({ + ...optionalSenderFieldShape, ...commonSchema, - ...senderFieldSchema, ...receiverFieldSchema, amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0)), }) @@ -42,7 +43,7 @@ export function PaymentTransactionBuilder({ mode, transaction, activeAccount, on onSubmit({ id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.Payment, - sender: data.sender, + sender: await resolveSenderAddress(data.sender), receiver: data.receiver, amount: data.amount, fee: data.fee, @@ -55,7 +56,7 @@ export function PaymentTransactionBuilder({ mode, transaction, activeAccount, on const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: transaction.sender, + sender: asTransactionSender(transaction.sender), receiver: transaction.receiver, amount: transaction.amount, fee: transaction.fee, @@ -92,7 +93,7 @@ export function PaymentTransactionBuilder({ mode, transaction, activeAccount, on {helper.addressField({ field: 'sender', label: 'Sender', - helpText: 'Account to pay from. Sends the transaction and pays the fee', + helpText: 'Account to pay from. Sends the transaction and pays the fee - optional for simulating', placeholder: ZERO_ADDRESS, })} {helper.addressField({ diff --git a/src/features/transaction-wizard/components/transactions-builder.tsx b/src/features/transaction-wizard/components/transactions-builder.tsx index e4101fc2..f8b72d7f 100644 --- a/src/features/transaction-wizard/components/transactions-builder.tsx +++ b/src/features/transaction-wizard/components/transactions-builder.tsx @@ -39,6 +39,7 @@ import { parseCallAbiMethodError, parseSimulateAbiMethodError } from '@/features export const transactionTypeLabel = 'Transaction type' export const sendButtonLabel = 'Send' const connectWalletMessage = 'Please connect a wallet' +const onlySimulateOptionalSenderMessage = 'Auto populated the sender - only simulate is enabled' export const addTransactionLabel = 'Add Transaction' export const transactionGroupLabel = 'Transaction Group' @@ -170,6 +171,7 @@ export function TransactionsBuilder({ stateChange: true, }), } satisfies SimulateOptions + const result = await (requireSignaturesOnSimulate ? (await buildComposer(transactions)).simulate(simulateConfig) : (await buildComposerWithEmptySignatures(transactions)).simulate({ @@ -327,6 +329,16 @@ export function TransactionsBuilder({ }, [activeAddress, commonButtonDisableProps, requireSignaturesOnSimulate]) const sendButtonDisabledProps = useMemo(() => { + // derive it, don't store it + const hasAutoPopulatedSender = transactions.some((t) => t.sender?.autoPopulated === true) + + if (hasAutoPopulatedSender) { + return { + disabled: true, + disabledReason: onlySimulateOptionalSenderMessage, + } + } + if (!activeAddress) { return { disabled: true, @@ -335,7 +347,7 @@ export function TransactionsBuilder({ } return commonButtonDisableProps - }, [activeAddress, commonButtonDisableProps]) + }, [transactions, activeAddress, commonButtonDisableProps]) return (
diff --git a/src/features/transaction-wizard/components/transactions-table.tsx b/src/features/transaction-wizard/components/transactions-table.tsx index 2aaa9a78..9c996cfb 100644 --- a/src/features/transaction-wizard/components/transactions-table.tsx +++ b/src/features/transaction-wizard/components/transactions-table.tsx @@ -216,6 +216,7 @@ const getTableColumns = ({ return transactionPositions.get(transaction.id)! }, }, + { header: 'Type', accessorFn: (item) => asTransactionLabelFromBuildableTransactionType(item.type), diff --git a/src/features/transaction-wizard/data/common.ts b/src/features/transaction-wizard/data/common.ts index dab3f6e6..5c714975 100644 --- a/src/features/transaction-wizard/data/common.ts +++ b/src/features/transaction-wizard/data/common.ts @@ -36,6 +36,7 @@ export const optionalAddressFieldSchema = z message: invalidAddressOrNfdMessage, }), resolvedAddress: z.string().optional(), + autoPopulated: z.boolean().optional(), }) .superRefine((field, ctx) => { if (field.value && (!field.resolvedAddress || !isAddress(field.resolvedAddress))) { @@ -48,6 +49,12 @@ export const optionalAddressFieldSchema = z }) export const senderFieldSchema = { sender: addressFieldSchema } + +// TODO Arthur - Added this shape to make the sender optional in the forms that required it +export const optionalSenderFieldShape = { + sender: optionalAddressFieldSchema, +} as const + export const receiverFieldSchema = { receiver: addressFieldSchema } export const noteFieldSchema = { note: zfd.text(z.string().optional()) } diff --git a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts index 148e978b..a6cced05 100644 --- a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts +++ b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts @@ -1,5 +1,5 @@ import { Address } from '@/features/accounts/data/types' -import { AddressOrNfd } from '../models' +import { AddressOrNfd, TransactionSender } from '../models' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): AddressOrNfd => { @@ -16,15 +16,24 @@ export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): } satisfies AddressOrNfd } -export const asOptionalAddressOrNfd = (addressOrNfdSchema: Partial) => { - return addressOrNfdSchema.value && addressOrNfdSchema.resolvedAddress - ? ({ value: addressOrNfdSchema.value, resolvedAddress: addressOrNfdSchema.resolvedAddress } satisfies AddressOrNfd) - : undefined +export const asTransactionSender = (transactionSender?: TransactionSender): TransactionSender => { + const emptySender: TransactionSender = { + value: undefined, + resolvedAddress: undefined, + autoPopulated: false, + } + if (!transactionSender) return emptySender + if (transactionSender.autoPopulated) return emptySender + + return transactionSender.value && transactionSender.resolvedAddress + ? { value: transactionSender.value, resolvedAddress: transactionSender.resolvedAddress, autoPopulated: transactionSender.autoPopulated } + : emptySender } export const asOptionalAddressOrNfdSchema = (address?: Address) => { return { value: address, resolvedAddress: address, + autoPopulated: false, } } diff --git a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts index 791d0dd8..14f4c049 100644 --- a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts +++ b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts @@ -86,8 +86,8 @@ export const asPaymentTransactionParams = ( transaction: BuildPaymentTransactionResult | BuildAccountCloseTransactionResult ): PaymentParams => { return { - sender: transaction.sender.resolvedAddress, - receiver: transaction.receiver ? transaction.receiver.resolvedAddress : transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, + receiver: transaction.receiver ? transaction.receiver.resolvedAddress : (transaction.sender?.resolvedAddress ?? 'LOL IDK'), closeRemainderTo: 'closeRemainderTo' in transaction ? transaction.closeRemainderTo.resolvedAddress : undefined, amount: algos(transaction.amount ?? 0), note: transaction.note, @@ -123,7 +123,7 @@ export const asMethodCallParams = async (transaction: BuildMethodCallTransaction ) return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, appId: BigInt(transaction.applicationId), method: transaction.methodDefinition.abiMethod, args: args, @@ -158,7 +158,7 @@ const asMethodCallTransactions = async (transaction: BuildMethodCallTransactionR export const asAppCallTransactionParams = (transaction: BuildAppCallTransactionResult): AppCallParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, appId: BigInt(transaction.applicationId), args: transaction.args.map((arg) => base64ToBytes(arg)), onComplete: transaction.onComplete, @@ -181,7 +181,7 @@ const asAppCallTransaction = async (transaction: BuildAppCallTransactionResult): export const asApplicationCreateTransactionParams = (transaction: BuildApplicationCreateTransactionResult): AppCreateParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, args: transaction.args.map((arg) => base64ToBytes(arg)), onComplete: transaction.onComplete, approvalProgram: base64ToBytes(transaction.approvalProgram), @@ -206,7 +206,7 @@ const asApplicationCreateTransaction = async (transaction: BuildApplicationCreat export const asApplicationUpdateTransactionParams = (transaction: BuildApplicationUpdateTransactionResult): AppUpdateParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, appId: BigInt(transaction.applicationId), args: transaction.args.map((arg) => base64ToBytes(arg)), approvalProgram: base64ToBytes(transaction.approvalProgram), @@ -239,8 +239,8 @@ export const asAssetTransferTransactionParams = ( amount = BigInt(convertedAmount.toString()) } return { - sender: transaction.sender.resolvedAddress, - receiver: 'receiver' in transaction ? transaction.receiver.resolvedAddress : transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, + receiver: 'receiver' in transaction ? transaction.receiver.resolvedAddress : transaction.sender.resolvedAddress!, clawbackTarget: 'clawbackTarget' in transaction ? transaction.clawbackTarget.resolvedAddress : undefined, closeAssetTo: 'closeRemainderTo' in transaction ? transaction.closeRemainderTo.resolvedAddress : undefined, assetId: BigInt(transaction.asset.id), @@ -259,7 +259,7 @@ const asAssetTransferTransaction = async ( ): Promise => { if ( transaction.type === BuildableTransactionType.AssetClawback && - (!transaction.asset.clawback || transaction.sender.resolvedAddress !== transaction.asset.clawback) + (!transaction.asset.clawback || transaction.sender.resolvedAddress! !== transaction.asset.clawback) ) { throw new Error('Invalid clawback transaction') } @@ -270,7 +270,7 @@ const asAssetTransferTransaction = async ( export const asAssetCreateTransactionParams = (transaction: BuildAssetCreateTransactionResult): AssetCreateParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, total: transaction.total, decimals: transaction.decimals, assetName: transaction.assetName, @@ -294,7 +294,7 @@ const asAssetCreateTransaction = async (transaction: BuildAssetCreateTransaction const asAssetReconfigureTransactionParams = (transaction: BuildAssetReconfigureTransactionResult): AssetConfigParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, assetId: BigInt(transaction.asset.id), manager: transaction.manager ? transaction.manager.resolvedAddress : undefined, reserve: transaction.reserve ? transaction.reserve.resolvedAddress : undefined, @@ -312,7 +312,7 @@ const asAssetReconfigureTransaction = async (transaction: BuildAssetReconfigureT const asAssetDestroyTransactionParams = (transaction: BuildAssetDestroyTransactionResult): AssetDestroyParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, assetId: BigInt(transaction.asset.id), } } @@ -338,7 +338,7 @@ export const asAssetConfigTransactionParams = ( export const asAssetFreezeTransactionParams = (transaction: BuildAssetFreezeTransactionResult): AssetFreezeParams => { return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, assetId: BigInt(transaction.asset.id), account: transaction.freezeTarget.resolvedAddress, frozen: transaction.frozen, @@ -348,7 +348,7 @@ export const asAssetFreezeTransactionParams = (transaction: BuildAssetFreezeTran } } const asAssetFreezeTransaction = async (transaction: BuildAssetFreezeTransactionResult): Promise => { - if (!transaction.asset.freeze || transaction.sender.resolvedAddress !== transaction.asset.freeze) { + if (!transaction.asset.freeze || transaction.sender.resolvedAddress! !== transaction.asset.freeze) { throw new Error('Invalid freeze transaction') } @@ -365,7 +365,7 @@ export const asKeyRegistrationTransactionParams = ( invariant(transaction.stateProofKey, 'State proof key is required') return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, voteKey: Uint8Array.from(Buffer.from(transaction.voteKey, 'base64')), selectionKey: Uint8Array.from(Buffer.from(transaction.selectionKey, 'base64')), stateProofKey: Uint8Array.from(Buffer.from(transaction.stateProofKey, 'base64')), @@ -379,7 +379,7 @@ export const asKeyRegistrationTransactionParams = ( } return { - sender: transaction.sender.resolvedAddress, + sender: transaction.sender.resolvedAddress!, } } @@ -391,10 +391,10 @@ const asKeyRegistrationTransaction = async (transaction: BuildKeyRegistrationTra : algorandClient.createTransaction.offlineKeyRegistration(params)) } -const asFee = (fee: BuildAssetCreateTransactionResult['fee']) => +export const asFee = (fee: BuildAssetCreateTransactionResult['fee']) => !fee.setAutomatically && fee.value != null ? { staticFee: algos(fee.value) } : undefined -const asValidRounds = (validRounds: BuildAssetCreateTransactionResult['validRounds']) => +export const asValidRounds = (validRounds: BuildAssetCreateTransactionResult['validRounds']) => !validRounds.setAutomatically && validRounds.firstValid && validRounds.lastValid ? { firstValidRound: validRounds.firstValid, diff --git a/src/features/transaction-wizard/mappers/as-description-list-items.tsx b/src/features/transaction-wizard/mappers/as-description-list-items.tsx index 2cfcb5ed..72a6ab05 100644 --- a/src/features/transaction-wizard/mappers/as-description-list-items.tsx +++ b/src/features/transaction-wizard/mappers/as-description-list-items.tsx @@ -49,6 +49,7 @@ import { asAssetDisplayAmount } from '@/features/common/components/display-asset import { AddressOrNfdLink } from '@/features/accounts/components/address-or-nfd-link' import { DecodedAbiStruct } from '@/features/abi-methods/components/decoded-abi-struct' import { ArgumentDefinition } from '@/features/applications/models' +import TransactionSenderLink from '@/features/accounts/components/transaction-sender-link' export const asDescriptionListItems = ( transaction: BuildTransactionResult, @@ -101,7 +102,7 @@ const asPaymentTransaction = (txn: BuildPaymentTransactionResult | BuildAccountC return [ { dt: 'Sender', - dd: , + dd: , }, ...('closeRemainderTo' in params && params.closeRemainderTo ? [ @@ -141,7 +142,7 @@ const asAssetTransferTransaction = ( }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Receiver', @@ -193,7 +194,7 @@ const asAssetConfigTransaction = ( ...('decimals' in params && params.decimals !== undefined ? [{ dt: 'Decimals', dd: params.decimals }] : []), { dt: transaction.type === BuildableTransactionType.AssetCreate ? 'Creator' : 'Sender', - dd: , + dd: , }, ...('manager' in params && params.manager ? [ @@ -248,7 +249,7 @@ const asAssetFreezeTransaction = (transaction: BuildAssetFreezeTransactionResult }, { dt: 'Sender', - dd: , + dd: , }, ...('account' in params && params.account ? [ @@ -274,7 +275,7 @@ const asKeyRegistrationTransaction = (transaction: BuildKeyRegistrationTransacti return [ { dt: 'Sender', - dd: , + dd: , }, { dt: 'Registration', @@ -386,7 +387,7 @@ const asAppCallTransaction = (transaction: BuildAppCallTransactionResult): Descr }, { dt: 'Sender', - dd: , + dd: , }, ...(transaction.extraProgramPages !== undefined ? [ @@ -439,7 +440,7 @@ const asMethodCallTransaction = ( }, { dt: 'Sender', - dd: , + dd: , }, ...(transaction.extraProgramPages !== undefined ? [ @@ -699,7 +700,7 @@ const asApplicationCreateTransaction = (transaction: BuildApplicationCreateTrans }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Approval program', @@ -762,7 +763,7 @@ const asApplicationUpdateTransaction = (transaction: BuildApplicationUpdateTrans }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Approval program', diff --git a/src/features/transaction-wizard/models/index.ts b/src/features/transaction-wizard/models/index.ts index 969ee2ca..dcfd882c 100644 --- a/src/features/transaction-wizard/models/index.ts +++ b/src/features/transaction-wizard/models/index.ts @@ -65,9 +65,15 @@ export type AddressOrNfd = { resolvedAddress: Address } +export type TransactionSender = { + value: Address | Nfd | undefined + resolvedAddress: Address | undefined + autoPopulated?: boolean +} + type CommonBuildTransactionResult = { id: string - sender: AddressOrNfd + sender: TransactionSender fee: { setAutomatically: boolean value?: number diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index 841056ac..91f6d09d 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -156,6 +156,83 @@ describe('transaction-wizard-page', () => { } ) }) + + it('Can add a payment transaction without defining a sender address and the sender gets auto populated', async () => { + const { testAccount } = localnet.context + const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) + + await executeComponentTest( + () => { + return render() + }, + async (component, user) => { + const addTransactionButton = await waitFor(() => { + const addTransactionButton = component.getByRole('button', { name: addTransactionLabel }) + expect(addTransactionButton).not.toBeDisabled() + return addTransactionButton! + }) + await user.click(addTransactionButton) + + const receiverInput = await component.findByLabelText(/Receiver/) + fireEvent.input(receiverInput, { + target: { value: testAccount2.addr }, + }) + + const amountInput = await component.findByLabelText(/Amount/) + fireEvent.input(amountInput, { + target: { value: '0.5' }, + }) + + const addButton = await waitFor(() => { + const addButton = component.getByRole('button', { name: 'Add' }) + expect(addButton).not.toBeDisabled() + return addButton! + }) + await user.click(addButton) + + const senderContent = await waitFor(() => { + return component.getByText(testAccount.addr.toString()) + }) + expect(senderContent).toBeInTheDocument() + + const sendButton = await waitFor(() => { + const sendButton = component.getByRole('button', { name: sendButtonLabel }) + expect(sendButton).not.toBeDisabled() + return sendButton! + }) + await user.click(sendButton) + + const resultsDiv = await waitFor( + () => { + expect(component.queryByText('Required')).not.toBeInTheDocument() + return component.getByText(groupSendResultsLabel).parentElement! + }, + { timeout: 10_000 } + ) + + const transactionId = await waitFor( + () => { + const transactionLink = within(resultsDiv) + .getAllByRole('link') + .find((a) => a.getAttribute('href')?.startsWith('/localnet/transaction'))! + return transactionLink.getAttribute('href')!.split('/').pop()! + }, + { timeout: 10_000 } + ) + + const result = await localnet.context.waitForIndexerTransaction(transactionId) + expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` + TransactionPayment { + "amount": 500000n, + "closeAmount": 0n, + "closeRemainderTo": undefined, + "receiver": "${testAccount2.addr}", + } + `) + } + ) + }) }) describe('and a close account transaction is being sent', () => { @@ -212,11 +289,96 @@ describe('transaction-wizard-page', () => { target: { value: testAccount.addr }, }) + const receiverInput = await component.findByLabelText(/Receiver/) + fireEvent.input(receiverInput, { + target: { value: testAccount.addr }, + }) + const closeToInput = await component.findByLabelText(/Close remainder to/) fireEvent.input(closeToInput, { target: { value: testAccount2.addr }, }) + const amountInput = await component.findByLabelText(/Amount to pay/) + fireEvent.input(amountInput, { target: { value: '0' } }) + + const addButton = await waitFor(() => { + const addButton = component.getByRole('button', { name: 'Add' }) + expect(addButton).not.toBeDisabled() + return addButton! + }) + await user.click(addButton) + + const sendButton = await waitFor(() => { + const sendButton = component.getByRole('button', { name: sendButtonLabel }) + expect(sendButton).not.toBeDisabled() + return sendButton! + }) + await user.click(sendButton) + + const resultsDiv = await waitFor( + () => { + expect(component.queryByText('Required')).not.toBeInTheDocument() + return component.getByText(groupSendResultsLabel).parentElement! + }, + { timeout: 10_000 } + ) + + const transactionId = await waitFor( + () => { + const transactionLink = within(resultsDiv) + .getAllByRole('link') + .find((a) => a.getAttribute('href')?.startsWith('/localnet/transaction'))! + return transactionLink.getAttribute('href')!.split('/').pop()! + }, + { timeout: 10_000 } + ) + + const result = await localnet.context.waitForIndexerTransaction(transactionId) + expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` + TransactionPayment { + "amount": 0n, + "closeAmount": 9999000n, + "closeRemainderTo": "${testAccount2.addr}", + "receiver": "${testAccount.addr}", + } + `) + } + ) + }) + + it('can simulate a close account transaction without defining a sender address', async () => { + const { testAccount } = localnet.context + const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) + + await executeComponentTest( + () => { + return render() + }, + async (component, user) => { + const addTransactionButton = await waitFor(() => { + const addTransactionButton = component.getByRole('button', { name: addTransactionLabel }) + expect(addTransactionButton).not.toBeDisabled() + return addTransactionButton! + }) + await user.click(addTransactionButton) + + await selectOption(component.baseElement, user, transactionTypeLabel, 'Account Close (pay)') + + const receiverInput = await component.findByLabelText(/Receiver/) + fireEvent.input(receiverInput, { + target: { value: testAccount.addr }, + }) + + const closeToInput = await component.findByLabelText(/Close remainder to/) + fireEvent.input(closeToInput, { + target: { value: testAccount2.addr }, + }) + + const amountInput = await component.findByLabelText(/Amount to pay/) + fireEvent.input(amountInput, { target: { value: '0' } }) + const addButton = await waitFor(() => { const addButton = component.getByRole('button', { name: 'Add' }) expect(addButton).not.toBeDisabled() @@ -413,6 +575,78 @@ describe('transaction-wizard-page', () => { } ) }) + + it('succeeds when sending an op-up transaction', async () => { + const { testAccount } = localnet.context + + await executeComponentTest( + () => { + return render() + }, + async (component, user) => { + const addTransactionButton = await waitFor(() => { + const addTransactionButton = component.getByRole('button', { name: addTransactionLabel }) + expect(addTransactionButton).not.toBeDisabled() + return addTransactionButton! + }) + await user.click(addTransactionButton) + + await selectOption(component.baseElement, user, transactionTypeLabel, 'Application Create (appl)') + + const senderInput = await component.findByLabelText(/Sender/) + fireEvent.input(senderInput, { + target: { value: testAccount.addr }, + }) + + const approvalProgramInput = await component.findByLabelText(/Approval program/) + fireEvent.input(approvalProgramInput, { + target: { value: 'CoEBQw==' }, + }) + + const clearStateProgramInput = await component.findByLabelText(/Clear state program/) + fireEvent.input(clearStateProgramInput, { + target: { value: 'CoEBQw==' }, + }) + + await selectOption(component.baseElement, user, /On complete/, 'Delete') + + const addButton = await waitFor(() => { + const addButton = component.getByRole('button', { name: 'Add' }) + expect(addButton).not.toBeDisabled() + return addButton! + }) + await user.click(addButton) + + const sendButton = await waitFor(() => { + const sendButton = component.getByRole('button', { name: sendButtonLabel }) + expect(sendButton).not.toBeDisabled() + return sendButton! + }) + await user.click(sendButton) + + const resultsDiv = await waitFor( + () => { + expect(component.queryByText('Required')).not.toBeInTheDocument() + return component.getByText(groupSendResultsLabel).parentElement! + }, + { timeout: 10_000 } + ) + + const transactionId = await waitFor( + () => { + const transactionLink = within(resultsDiv) + .getAllByRole('link') + .find((a) => a.getAttribute('href')?.startsWith('/localnet/transaction'))! + return transactionLink.getAttribute('href')!.split('/').pop()! + }, + { timeout: 10_000 } + ) + + const result = await localnet.context.waitForIndexerTransaction(transactionId) + expect(result.transaction.sender).toBe(testAccount.addr.toString()) + } + ) + }) }) describe('and an application update transaction is being sent', () => { diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 80cac7f0..2bbe9724 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -19,6 +19,7 @@ export const sendButtonLabel = 'Send' export function TransactionWizardPage() { const [sendResults, setSendResults] = useState(undefined) const searchParamsTransactions = useTransactionSearchParamsBuilder() + useTitle('Transaction Wizard') const renderTransactionResults = useCallback((result: SendTransactionResults, simulateResponse?: algosdk.modelsv2.SimulateResponse) => { @@ -45,6 +46,7 @@ export function TransactionWizardPage() { async (result: SimulateResult) => { renderTransactionResults(result, result.simulateResponse) }, + [renderTransactionResults] ) diff --git a/src/features/transaction-wizard/utils/resolve-sender-address.ts b/src/features/transaction-wizard/utils/resolve-sender-address.ts new file mode 100644 index 00000000..b70a1930 --- /dev/null +++ b/src/features/transaction-wizard/utils/resolve-sender-address.ts @@ -0,0 +1,48 @@ +import { OptionalSenderFieldSchema } from '@/features/forms/components/address-form-item' +import { + TESTNET_FEE_SINK_ADDRESS, + MAINNET_FEE_SINK_ADDRESS, + networkConfigAtom, + BETANET_FEE_SINK_ADDRESS, + FNET_FEE_SINK_ADDRESS, +} from '@/features/network/data' +import { AddressOrNfd, TransactionSender } from '../models' +import { settingsStore } from '@/features/settings/data' +import { betanetId, mainnetId, testnetId, fnetId, localnetId } from '@/features/network/data' +import { algorandClient } from '@/features/common/data/algo-client' + +export default async function resolveSenderAddress( + data: T +): Promise { + const { id: networkId } = settingsStore.get(networkConfigAtom) + + const val = data?.value ?? '' + const res = data?.resolvedAddress ?? '' + + const isEmpty = !val && !res + + if (isEmpty) { + if (networkId === mainnetId) { + return { value: MAINNET_FEE_SINK_ADDRESS, resolvedAddress: MAINNET_FEE_SINK_ADDRESS, autoPopulated: true } + } + if (networkId === localnetId) { + const address = (await algorandClient.account.localNetDispenser()).addr.toString() + return { value: address, resolvedAddress: address, autoPopulated: true } + } + if (networkId === fnetId) { + return { value: FNET_FEE_SINK_ADDRESS, resolvedAddress: FNET_FEE_SINK_ADDRESS, autoPopulated: true } + } + if (networkId === betanetId) { + return { value: BETANET_FEE_SINK_ADDRESS, resolvedAddress: BETANET_FEE_SINK_ADDRESS, autoPopulated: true } + } + if (networkId === testnetId) { + return { value: TESTNET_FEE_SINK_ADDRESS, resolvedAddress: TESTNET_FEE_SINK_ADDRESS, autoPopulated: true } + } + } + + return { + value: val || res, + resolvedAddress: res || val, + autoPopulated: false, + } +} diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index ca11a63d..d7d4050e 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -193,11 +193,6 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, { key: 'receiver[0]', mode: 'missing', @@ -209,12 +204,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0: The number NaN cannot be converted to a BigInt because it is not an integer', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'receiver[0]', mode: 'invalid', @@ -366,11 +356,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'total[0]', mode: 'missing', @@ -382,12 +368,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: decimals', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'total[0]', mode: 'invalid', @@ -568,11 +549,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'assetid[0]', mode: 'missing', @@ -584,12 +561,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'assetid[0]', mode: 'invalid', @@ -757,11 +729,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'assetid[0]', mode: 'missing', @@ -778,12 +746,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'assetid[0]', mode: 'invalid', @@ -970,11 +933,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'receiver[0]', mode: 'missing', @@ -996,12 +955,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'receiver[0]', mode: 'invalid', @@ -1196,11 +1150,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'assetid[0]', mode: 'missing', @@ -1217,12 +1167,6 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value, sender.value', - }, { key: 'assetid[0]', mode: 'invalid', @@ -1418,11 +1362,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'assetid[0]', mode: 'missing', @@ -1439,12 +1379,7 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value', - }, + { key: 'assetid[0]', mode: 'invalid', @@ -1663,11 +1598,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'freezeto[0]', mode: 'missing', @@ -1689,12 +1620,6 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value, sender.value', - }, { key: 'freezeto[0]', mode: 'invalid', @@ -1956,11 +1881,7 @@ describe('Render transactions page with search params', () => { it.each([ // Missing required field cases - { - key: 'sender[0]', - mode: 'missing', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-resolvedAddress', - }, + { key: 'receiver[0]', mode: 'missing', @@ -1992,12 +1913,6 @@ describe('Render transactions page with search params', () => { expected: 'Error in transaction at index 0 in the following fields: asset-id', }, // Invalid field value cases - { - key: 'sender[0]', - mode: 'invalid', - value: 'invalid-address', - expected: 'Error in transaction at index 0 in the following fields: sender-value, sender-value, sender.value', - }, { key: 'receiver[0]', mode: 'invalid', diff --git a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts index 55d5bee8..29d7d80b 100644 --- a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts +++ b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts @@ -28,6 +28,7 @@ import { randomGuid } from '@/utils/random-guid' import algosdk from 'algosdk' import { microAlgo } from '@algorandfoundation/algokit-utils' import Decimal from 'decimal.js' +import { asTransactionSender } from '../mappers/as-address-or-nfd' // This is a workaround to make the online field a boolean instead of a string. // A string type is used in the form schema because of the value of radio buttons cant be boolean @@ -38,10 +39,7 @@ const keyRegFormSchema = keyRegistrationFormSchema.innerType().extend({ const transformKeyRegistrationTransaction = (params: BaseSearchParamTransaction): BuildKeyRegistrationTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.KeyRegistration, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), online: Boolean(params.votekey), fee: params.fee ? { setAutomatically: false, value: microAlgo(Number(params.fee)).algo } : { setAutomatically: true }, voteKey: params.votekey, @@ -60,10 +58,8 @@ const transformKeyRegistrationTransaction = (params: BaseSearchParamTransaction) const transformPaymentTransaction = (params: BaseSearchParamTransaction): BuildPaymentTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.Payment, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + receiver: { value: params.receiver, resolvedAddress: params.receiver, @@ -85,10 +81,8 @@ const defaultOptionalAddress = { const transformAssetCreateTransaction = (params: BaseSearchParamTransaction): BuildAssetCreateTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetCreate, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + total: BigInt(params.total), decimals: Number(params.decimals), assetName: params.assetname, @@ -132,10 +126,8 @@ const transformAssetCreateTransaction = (params: BaseSearchParamTransaction): Bu const transformAssetOptInTransaction = (params: BaseSearchParamTransaction): BuildAssetOptInTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetOptIn, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + asset: { id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, @@ -153,10 +145,8 @@ const transformAssetOptInTransaction = (params: BaseSearchParamTransaction): Bui const transformAssetOptOutTransaction = (params: BaseSearchParamTransaction): BuildAssetOptOutTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetOptOut, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + asset: { id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, @@ -179,10 +169,8 @@ const transformAssetOptOutTransaction = (params: BaseSearchParamTransaction): Bu const transformAssetTransferTransaction = (params: BaseSearchParamTransaction): BuildAssetTransferTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetTransfer, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + receiver: { value: params.receiver, resolvedAddress: params.receiver, @@ -206,10 +194,8 @@ const transformAssetTransferTransaction = (params: BaseSearchParamTransaction): const transformAssetReconfigureTransaction = (params: BaseSearchParamTransaction): BuildAssetReconfigureTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetReconfigure, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + asset: { id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, @@ -252,10 +238,8 @@ const transformAssetReconfigureTransaction = (params: BaseSearchParamTransaction const transformAssetFreezeTransaction = (params: BaseSearchParamTransaction): BuildAssetFreezeTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetFreeze, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + freezeTarget: { value: params.freezeto, resolvedAddress: params.freezeto, @@ -279,10 +263,8 @@ const transformAssetFreezeTransaction = (params: BaseSearchParamTransaction): Bu const transformAssetDestroyTransaction = (params: BaseSearchParamTransaction): BuildAssetDestroyTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetDestroy, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + asset: { id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, @@ -300,10 +282,8 @@ const transformAssetDestroyTransaction = (params: BaseSearchParamTransaction): B const transformAssetClawbackTransaction = (params: BaseSearchParamTransaction): BuildAssetClawbackTransactionResult => ({ id: randomGuid(), type: BuildableTransactionType.AssetClawback, - sender: { - value: params.sender, - resolvedAddress: params.sender, - }, + sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + receiver: { value: params.receiver, resolvedAddress: params.receiver, From d1951ef1b1bc7299fbb87cb7fd768aab969213a1 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Fri, 7 Nov 2025 02:26:17 -0800 Subject: [PATCH 03/18] chore(package-lock): update package lock to reflect dependencies from main --- package-lock.json | 3392 ++------------------------------------------- 1 file changed, 118 insertions(+), 3274 deletions(-) diff --git a/package-lock.json b/package-lock.json index b24a1a29..2894988c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,7 +135,6 @@ "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" @@ -147,7 +146,6 @@ "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@actions/io": "^1.0.1" } @@ -158,7 +156,6 @@ "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" @@ -169,8 +166,7 @@ "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@adobe/css-tools": { "version": "4.4.4", @@ -1255,7 +1251,6 @@ "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=14" } @@ -1682,13 +1677,13 @@ "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", - "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz", + "integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^16.0.0" + "@octokit/types": "^15.0.1" }, "engines": { "node": ">= 20" @@ -3502,7 +3497,6 @@ "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "compare-func": "^2.0.0" }, @@ -3516,7 +3510,6 @@ "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "meow": "^13.0.0" }, @@ -3533,7 +3526,6 @@ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -3596,14 +3588,14 @@ } }, "node_modules/@semantic-release/github": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-12.0.1.tgz", - "integrity": "sha512-BSC7Ko6aRPnH8ttVBpd3gC98LTiyPdmrmX4qHilLw5EZqVrXrXwcKp/JKUC5hgm0XpJACR3nPjgbfOjTJ75PIA==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.6.tgz", + "integrity": "sha512-ctDzdSMrT3H+pwKBPdyCPty6Y47X8dSrjd3aPZ5KKIKKWTwZBE9De8GtsH3TyAlw3Uyo2stegMx6rJMXKpJwJA==", "dev": true, "license": "MIT", "dependencies": { "@octokit/core": "^7.0.0", - "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-paginate-rest": "^13.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", @@ -3620,7 +3612,7 @@ "url-join": "^5.0.0" }, "engines": { - "node": "^22.14.0 || >= 24.10.0" + "node": ">=20.8.1" }, "peerDependencies": { "semantic-release": ">=24.1.0" @@ -3646,21 +3638,6 @@ "clean-stack": "^5.2.0", "indent-string": "^5.0.0" }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/github/node_modules/aggregate-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", - "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "clean-stack": "^5.2.0", - "indent-string": "^5.0.0" - }, "engines": { "node": ">=18" }, @@ -3690,7 +3667,6 @@ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3704,7 +3680,6 @@ "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3734,7 +3709,6 @@ "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -4006,7 +3980,6 @@ "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "compare-func": "^2.0.0" }, @@ -4020,7 +3993,6 @@ "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "meow": "^13.0.0" }, @@ -4050,7 +4022,6 @@ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -4311,9 +4282,9 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", - "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", + "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", "dev": true, "license": "MIT", "dependencies": { @@ -4321,39 +4292,39 @@ "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", - "magic-string": "^0.30.19", + "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.1.16" + "tailwindcss": "4.1.17" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", - "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", + "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", "dev": true, "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.16", - "@tailwindcss/oxide-darwin-arm64": "4.1.16", - "@tailwindcss/oxide-darwin-x64": "4.1.16", - "@tailwindcss/oxide-freebsd-x64": "4.1.16", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", - "@tailwindcss/oxide-linux-x64-musl": "4.1.16", - "@tailwindcss/oxide-wasm32-wasi": "4.1.16", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" + "@tailwindcss/oxide-android-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-x64": "4.1.17", + "@tailwindcss/oxide-freebsd-x64": "4.1.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-x64-musl": "4.1.17", + "@tailwindcss/oxide-wasm32-wasi": "4.1.17", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", - "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", + "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", "cpu": [ "arm64" ], @@ -4368,9 +4339,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", - "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", + "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", "cpu": [ "arm64" ], @@ -4385,9 +4356,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", - "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", + "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", "cpu": [ "x64" ], @@ -4402,9 +4373,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", - "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", + "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", "cpu": [ "x64" ], @@ -4419,9 +4390,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", - "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", + "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", "cpu": [ "arm" ], @@ -4436,9 +4407,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", - "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", + "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", "cpu": [ "arm64" ], @@ -4453,9 +4424,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", - "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", + "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", "cpu": [ "arm64" ], @@ -4470,9 +4441,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", - "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", + "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", "cpu": [ "x64" ], @@ -4487,9 +4458,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", - "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", + "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", "cpu": [ "x64" ], @@ -4504,9 +4475,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", - "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", + "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -4522,8 +4493,8 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", + "@emnapi/core": "^1.6.0", + "@emnapi/runtime": "^1.6.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", @@ -4534,9 +4505,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", - "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", + "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", "cpu": [ "arm64" ], @@ -4551,9 +4522,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", - "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", + "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", "cpu": [ "x64" ], @@ -4568,29 +4539,29 @@ } }, "node_modules/@tailwindcss/postcss": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.16.tgz", - "integrity": "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz", + "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==", "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.16", - "@tailwindcss/oxide": "4.1.16", + "@tailwindcss/node": "4.1.17", + "@tailwindcss/oxide": "4.1.17", "postcss": "^8.4.41", - "tailwindcss": "4.1.16" + "tailwindcss": "4.1.17" } }, "node_modules/@tailwindcss/vite": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz", - "integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.17.tgz", + "integrity": "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==", "dev": true, "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.1.16", - "@tailwindcss/oxide": "4.1.16", - "tailwindcss": "4.1.16" + "@tailwindcss/node": "4.1.17", + "@tailwindcss/oxide": "4.1.17", + "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" @@ -5903,7 +5874,6 @@ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 14" } @@ -5979,7 +5949,6 @@ "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "environment": "^1.0.0" }, @@ -8006,7 +7975,6 @@ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8036,7 +8004,6 @@ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mimic-fn": "^4.0.0" }, @@ -8066,7 +8033,6 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=14" }, @@ -9093,20 +9059,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -9207,7 +9159,6 @@ "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "through2": "~2.0.0" } @@ -9218,7 +9169,6 @@ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -9720,9 +9670,9 @@ } }, "node_modules/html2canvas-pro": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/html2canvas-pro/-/html2canvas-pro-1.5.12.tgz", - "integrity": "sha512-egtJIe6YXMKSLX/ls400OJD6tzEVtATJOE++mnXmxMWyqcu9HDXDoLiWeXnGv45QW2ZaIiDlXw46Gxqrqw6SEw==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/html2canvas-pro/-/html2canvas-pro-1.5.13.tgz", + "integrity": "sha512-//ksb3JLA+ewSxFODyb5YH6xqRLpe6Kt1i7Zyr5eqHmfcNt0bm8MpzSQjOK2qu6cCv13wqWtOZrCOpA+//EhaA==", "license": "MIT", "dependencies": { "css-line-break": "^2.1.0", @@ -11146,7 +11096,6 @@ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -11388,7 +11337,6 @@ "integrity": "sha512-T9BPOmEOhp6SmV25SwLVcHK4E6JyG/coH3C6F1NjNXSziv/fd4GmsqMk8YR6qpPOswfaOCApSNkZv6fxoaYFcQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-event": "^6.0.0", "type-fest": "^4.6.0", @@ -11407,7 +11355,6 @@ "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-timeout": "^6.1.2" }, @@ -11424,7 +11371,6 @@ "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=14.16" }, @@ -11743,9 +11689,9 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.6.tgz", - "integrity": "sha512-MCYMykvmiYScyUm7I6y0VCxpNq1rgd5v7kG8ks5dKtvmxRUUPjribX6mUoUNBbM5/3PhUyoelEWiKXGOz84c+w==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.12.0.tgz", + "integrity": "sha512-jzf2eVnd8+iWXN74dccLrHUw3i3hFVvNVQRWS4vBl2KxaUt7Tdur0Eyda/DODGFkZDu2P5MXaeLe/9Qx8PZkrg==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -16828,17 +16774,17 @@ } }, "node_modules/semantic-release": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-25.0.1.tgz", - "integrity": "sha512-0OCYLm0AfVilNGukM+w0C4aptITfuW1Mhvmz8LQliLeYbPOTFRCIJzoltWWx/F5zVFe6np9eNatBUHdAvMFeZg==", + "version": "24.2.9", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz", + "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==", "dev": true, "license": "MIT", "dependencies": { - "@semantic-release/commit-analyzer": "^13.0.1", + "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", - "@semantic-release/github": "^12.0.0", - "@semantic-release/npm": "^13.1.1", - "@semantic-release/release-notes-generator": "^14.1.0", + "@semantic-release/github": "^11.0.0", + "@semantic-release/npm": "^12.0.2", + "@semantic-release/release-notes-generator": "^14.0.0-beta.1", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", @@ -16849,7 +16795,7 @@ "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^4.0.0", - "hosted-git-info": "^9.0.0", + "hosted-git-info": "^8.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "marked": "^15.0.0", @@ -16862,23 +16808,26 @@ "semver": "^7.3.2", "semver-diff": "^5.0.0", "signale": "^1.2.1", - "yargs": "^18.0.0" + "yargs": "^17.5.1" }, "bin": { "semantic-release": "bin/semantic-release.js" }, "engines": { - "node": "^22.14.0 || >= 24.10.0" + "node": ">=20.8.1" } }, "node_modules/semantic-release-export-data": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/semantic-release-export-data/-/semantic-release-export-data-1.2.0.tgz", - "integrity": "sha512-/9+yQWFieiN0KB7YA0TTCXHml7d2tlNLkprLjUOKf8XDQlJ6ZK9gkw0dJJ/8/kBzeuUPq8aZR2n0rYmuYCz7Xg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semantic-release-export-data/-/semantic-release-export-data-1.0.1.tgz", + "integrity": "sha512-6vlgrrzzcMi/REhQd65Bh4dfSKmgwXOJ/Q2RVlT9WsU4Ya1T2qGpkSrMfG/n6oFRrqBdbDlyZgxNd94ziW+vSg==", "dev": true, "license": "MIT", + "dependencies": { + "@actions/core": "^1.10.0" + }, "peerDependencies": { - "semantic-release": ">=20" + "semantic-release": ">=18" } }, "node_modules/semantic-release/node_modules/@semantic-release/error": { @@ -16887,49 +16836,16 @@ "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/semantic-release/node_modules/@semantic-release/npm": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-13.1.1.tgz", - "integrity": "sha512-c4tlp3STYaTYORmMcLjiTaI8SLoxJ0Uf7IXkem8EyihuOM624wnaGuH4OuY2HHcsHDerNAQNzZ8VO6d4PMHSzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@actions/core": "^1.11.1", - "@semantic-release/error": "^4.0.0", - "aggregate-error": "^5.0.0", - "env-ci": "^11.2.0", - "execa": "^9.0.0", - "fs-extra": "^11.0.0", - "lodash-es": "^4.17.21", - "nerf-dart": "^1.0.0", - "normalize-url": "^8.0.0", - "npm": "^11.6.2", - "rc": "^1.2.8", - "read-pkg": "^9.0.0", - "registry-auth-token": "^5.0.0", - "semver": "^7.1.2", - "tempy": "^3.0.0" - }, - "engines": { - "node": "^22.14.0 || >= 24.10.0" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, "node_modules/semantic-release/node_modules/aggregate-error": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" @@ -16941,41 +16857,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/semantic-release/node_modules/clean-stack": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "escape-string-regexp": "5.0.0" }, @@ -16986,28 +16873,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/semantic-release/node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -17029,21 +16900,12 @@ } } }, - "node_modules/semantic-release/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/semantic-release/node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17057,7 +16919,6 @@ "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", @@ -17085,7 +16946,6 @@ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" @@ -17098,17 +16958,16 @@ } }, "node_modules/semantic-release/node_modules/hosted-git-info": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { - "lru-cache": "^11.1.0" + "lru-cache": "^10.0.1" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/semantic-release/node_modules/human-signals": { @@ -17117,7 +16976,6 @@ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=18.18.0" } @@ -17128,7 +16986,6 @@ "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17142,7 +16999,6 @@ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -17150,2949 +17006,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/semantic-release/node_modules/npm": { - "version": "11.6.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.6.2.tgz", - "integrity": "sha512-7iKzNfy8lWYs3zq4oFPa8EXZz5xt9gQNKJZau3B1ErLBb6bF7sBJ00x09485DOvRT2l5Gerbl3VlZNT57MxJVA==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/promise-spawn", - "@npmcli/redact", - "@npmcli/run-script", - "@sigstore/tuf", - "abbrev", - "archy", - "cacache", - "chalk", - "ci-info", - "cli-columns", - "fastest-levenshtein", - "fs-minipass", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minimatch", - "minipass", - "minipass-pipeline", - "ms", - "node-gyp", - "nopt", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "semver", - "spdx-expression-parse", - "ssri", - "supports-color", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which" - ], - "dev": true, - "license": "Artistic-2.0", - "peer": true, - "workspaces": [ - "docs", - "smoke-tests", - "mock-globals", - "mock-registry", - "workspaces/*" - ], - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.1.6", - "@npmcli/config": "^10.4.2", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/package-json": "^7.0.1", - "@npmcli/promise-spawn": "^8.0.3", - "@npmcli/redact": "^3.2.2", - "@npmcli/run-script": "^10.0.0", - "@sigstore/tuf": "^4.0.0", - "abbrev": "^3.0.1", - "archy": "~1.0.0", - "cacache": "^20.0.1", - "chalk": "^5.6.2", - "ci-info": "^4.3.1", - "cli-columns": "^4.0.0", - "fastest-levenshtein": "^1.0.16", - "fs-minipass": "^3.0.3", - "glob": "^11.0.3", - "graceful-fs": "^4.2.11", - "hosted-git-info": "^9.0.2", - "ini": "^5.0.0", - "init-package-json": "^8.2.2", - "is-cidr": "^6.0.1", - "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^10.0.3", - "libnpmdiff": "^8.0.9", - "libnpmexec": "^10.1.8", - "libnpmfund": "^7.0.9", - "libnpmorg": "^8.0.1", - "libnpmpack": "^9.0.9", - "libnpmpublish": "^11.1.2", - "libnpmsearch": "^9.0.1", - "libnpmteam": "^8.0.2", - "libnpmversion": "^8.0.2", - "make-fetch-happen": "^15.0.2", - "minimatch": "^10.0.3", - "minipass": "^7.1.1", - "minipass-pipeline": "^1.2.4", - "ms": "^2.1.2", - "node-gyp": "^11.4.2", - "nopt": "^8.1.0", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^7.1.2", - "npm-package-arg": "^13.0.1", - "npm-pick-manifest": "^11.0.1", - "npm-profile": "^12.0.0", - "npm-registry-fetch": "^19.0.0", - "npm-user-validate": "^3.0.0", - "p-map": "^7.0.3", - "pacote": "^21.0.3", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.1.0", - "semver": "^7.7.3", - "spdx-expression-parse": "^4.0.0", - "ssri": "^12.0.0", - "supports-color": "^10.2.2", - "tar": "^7.5.1", - "text-table": "~0.2.0", - "tiny-relative-date": "^2.0.2", - "treeverse": "^3.0.0", - "validate-npm-package-name": "^6.0.2", - "which": "^5.0.0" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/semantic-release/node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/agent": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^11.2.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.1.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/metavuln-calculator": "^9.0.2", - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/query": "^4.0.0", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^10.0.0", - "bin-links": "^5.0.0", - "cacache": "^20.0.1", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^9.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^11.2.1", - "minimatch": "^10.0.3", - "nopt": "^8.0.0", - "npm-install-checks": "^7.1.0", - "npm-package-arg": "^13.0.0", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "pacote": "^21.0.2", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "proggy": "^3.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "semver": "^7.3.7", - "ssri": "^12.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^4.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/config": { - "version": "10.4.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "ini": "^5.0.0", - "nopt": "^8.1.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/fs": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/git": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/promise-spawn": "^8.0.0", - "ini": "^5.0.0", - "lru-cache": "^11.2.1", - "npm-pick-manifest": "^11.0.1", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-bundled": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/package-json": "^7.0.0", - "glob": "^11.0.3", - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "9.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cacache": "^20.0.0", - "json-parse-even-better-errors": "^4.0.0", - "pacote": "^21.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/package-json": { - "version": "7.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^7.0.0", - "glob": "^11.0.3", - "hosted-git-info": "^9.0.0", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "8.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/redact": { - "version": "3.2.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@npmcli/run-script": { - "version": "10.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "node-gyp": "^11.0.0", - "proc-log": "^5.0.0", - "which": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/bundle": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/core": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.5.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/sign": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/tuf": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0", - "tuf-js": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@sigstore/verify": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/models": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/abbrev": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/agent-base": { - "version": "7.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/p-reduce": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", - "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/aproba": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/bin-links": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cmd-shim": "^7.0.0", - "npm-normalize-package-bin": "^4.0.0", - "proc-log": "^5.0.0", - "read-cmd-shim": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/binary-extensions": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cacache": { - "version": "20.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^11.0.3", - "lru-cache": "^11.1.0", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/chalk": { - "version": "5.6.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/chownr": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ci-info": { - "version": "4.3.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cidr-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "ip-regex": "5.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cmd-shim": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/debug": { - "version": "4.4.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/diff": { - "version": "8.0.2", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.2", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.16", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/foreground-child": { - "version": "3.3.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/fs-minipass": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/glob": { - "version": "11.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.0.3", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/hosted-git-info": { - "version": "9.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ignore-walk": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ini": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/init-package-json": { - "version": "8.2.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "npm-package-arg": "^13.0.0", - "promzard": "^2.0.0", - "read": "^4.0.0", - "semver": "^7.7.2", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^6.0.2" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ip-address": { - "version": "10.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ip-regex": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/is-cidr": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "cidr-regex": "5.0.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/isexe": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/jackspeak": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/just-diff": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/just-diff-apply": { - "version": "5.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmaccess": { - "version": "10.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmdiff": { - "version": "8.0.9", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^9.1.6", - "@npmcli/installed-package-contents": "^3.0.0", - "binary-extensions": "^3.0.0", - "diff": "^8.0.2", - "minimatch": "^10.0.3", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "tar": "^7.5.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmexec": { - "version": "10.1.8", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^9.1.6", - "@npmcli/package-json": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "read": "^4.0.0", - "semver": "^7.3.7", - "signal-exit": "^4.1.0", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.9", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^9.1.6" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmorg": { - "version": "8.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmpack": { - "version": "9.0.9", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^9.1.6", - "@npmcli/run-script": "^10.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmpublish": { - "version": "11.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.7", - "sigstore": "^4.0.0", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmsearch": { - "version": "9.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmteam": { - "version": "8.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/libnpmversion": { - "version": "8.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/lru-cache": { - "version": "11.2.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/make-fetch-happen": { - "version": "15.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/agent": "^4.0.0", - "cacache": "^20.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minimatch": { - "version": "10.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-collect": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-fetch": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/minizlib": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/mute-stream": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/negotiator": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp": { - "version": "11.4.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/agent": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/cacache": { - "version": "19.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/glob": { - "version": "10.4.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/jackspeak": { - "version": "3.4.3", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/lru-cache": { - "version": "10.4.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "14.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/node-gyp/node_modules/path-scurry": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/nopt": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-audit-report": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-bundled": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-install-checks": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-package-arg": { - "version": "13.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-packlist": { - "version": "10.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "ignore-walk": "^8.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-pick-manifest": { - "version": "11.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^13.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-profile": { - "version": "12.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-registry-fetch": "^19.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-registry-fetch": { - "version": "19.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/redact": "^3.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^15.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^13.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/npm-user-validate": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/p-map": { - "version": "7.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/package-json-from-dist": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/pacote": { - "version": "21.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^7.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^10.0.0", - "cacache": "^20.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^13.0.0", - "npm-packlist": "^10.0.1", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^4.0.0", - "ssri": "^12.0.0", - "tar": "^7.4.3" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/parse-conflict-json": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/path-scurry": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/proc-log": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/proggy": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/promise-call-limit": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/promzard": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "read": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "peer": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/read": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "mute-stream": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/read-cmd-shim": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/semver": { - "version": "7.7.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/sigstore": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.0.0", - "@sigstore/tuf": "^4.0.0", - "@sigstore/verify": "^3.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/socks": { - "version": "2.8.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/spdx-correct": { - "version": "3.2.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.5.0", - "dev": true, - "inBundle": true, - "license": "CC-BY-3.0", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.22", - "dev": true, - "inBundle": true, - "license": "CC0-1.0", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/ssri": { - "version": "12.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/supports-color": { - "version": "10.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tar": { - "version": "7.5.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tar/node_modules/yallist": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tiny-relative-date": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby": { - "version": "0.2.15", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/treeverse": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/tuf-js": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tufjs/models": "4.0.0", - "debug": "^4.4.1", - "make-fetch-happen": "^15.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/unique-filename": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/unique-slug": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/walk-up-path": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/which": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/write-file-atomic": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, "node_modules/semantic-release/node_modules/p-reduce": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -20106,7 +17042,6 @@ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -20120,7 +17055,6 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=14" }, @@ -20128,49 +17062,12 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/semantic-release/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/semantic-release/node_modules/strip-final-newline": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -20184,7 +17081,6 @@ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -20192,55 +17088,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/semantic-release/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/semantic-release/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -21196,9 +18043,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", - "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", "dev": true, "license": "MIT" }, @@ -21613,7 +18460,6 @@ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -21830,7 +18676,6 @@ "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -22100,9 +18945,9 @@ } }, "node_modules/vite": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", - "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", + "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -22349,8 +19194,7 @@ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", "dev": true, - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/whatwg-mimetype": { "version": "3.0.0", From fe99a1582e2fa5870453e4eb7455e74f455f40bd Mon Sep 17 00:00:00 2001 From: p2arthur Date: Sun, 9 Nov 2025 18:13:41 -0800 Subject: [PATCH 04/18] feat(search_params) add optional sender with auto populate to search params transaction builder --- .../components/transaction-sender-link.tsx | 17 +- .../forms/components/address-form-item.tsx | 4 +- .../account-close-transaction-builder.tsx | 15 +- .../app-call-transaction-builder.tsx | 13 +- ...application-create-transaction-builder.tsx | 8 +- ...application-update-transaction-builder.tsx | 8 +- .../asset-clawback-transaction-builder.tsx | 8 +- .../asset-create-transaction-builder.tsx | 8 +- .../asset-destroy-transaction-builder.tsx | 8 +- .../asset-freeze-transaction-builder.tsx | 8 +- .../asset-opt-in-transaction-builder.tsx | 8 +- .../asset-opt-out-transaction-builder.tsx | 8 +- .../asset-reconfigure-transaction-builder.tsx | 8 +- .../asset-transfer-transaction-builder.tsx | 8 +- .../key-registration-transaction-builder.tsx | 8 +- .../method-call-transaction-builder.tsx | 8 +- .../payment-transaction-builder.tsx | 8 +- .../components/transactions-builder.tsx | 1 - .../transaction-wizard/data/common.ts | 5 - .../mappers/as-address-or-nfd.ts | 9 +- .../mappers/as-algosdk-transactions.ts | 2 +- .../mappers/as-description-list-items.tsx | 2 +- .../transaction-wizard/models/index.ts | 4 +- .../transaction-wizard-page.tsx | 3 +- .../utils/resolve-sender-address.ts | 6 +- .../transactions-url-search-params.test.tsx | 514 +++++++++--------- .../transform-search-params-transactions.ts | 9 +- .../use-transaction-search-params-builder.ts | 55 +- 28 files changed, 385 insertions(+), 378 deletions(-) diff --git a/src/features/accounts/components/transaction-sender-link.tsx b/src/features/accounts/components/transaction-sender-link.tsx index 02042347..2769cbbc 100644 --- a/src/features/accounts/components/transaction-sender-link.tsx +++ b/src/features/accounts/components/transaction-sender-link.tsx @@ -2,11 +2,11 @@ import { Nfd } from '@/features/nfd/data/types' import { PropsWithChildren } from 'react' import { AddressOrNfdLink } from './address-or-nfd-link' -import { Address } from '../data/types' +import { Address } from 'algosdk' import { cn } from '@/features/common/utils' export type Props = PropsWithChildren<{ - address: Address + address: string | Address short?: boolean className?: string showCopyButton?: boolean @@ -15,17 +15,12 @@ export type Props = PropsWithChildren<{ autoPopulated?: boolean }> -export default function TransactionSenderLink({ address, short, showCopyButton, showQRButton, nfd, autoPopulated }: Props) { +export default function TransactionSenderLink(props: Props) { + const { autoPopulated, className, ...rest } = props + return (
- + {autoPopulated && ( diff --git a/src/features/forms/components/address-form-item.tsx b/src/features/forms/components/address-form-item.tsx index 4da1eca0..d0a1fd54 100644 --- a/src/features/forms/components/address-form-item.tsx +++ b/src/features/forms/components/address-form-item.tsx @@ -1,7 +1,7 @@ import { FieldPath, useFormContext } from 'react-hook-form' import { FormItemProps } from '@/features/forms/components/form-item' import { TextFormItem } from './text-form-item' -import { addressFieldSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' +import { addressFieldSchema, optionalAddressFieldSchema } from '@/features/transaction-wizard/data/common' import { useDebounce } from 'use-debounce' import { isNfd, useLoadableForwardLookupNfdResult } from '@/features/nfd/data' import { useCallback, useEffect } from 'react' @@ -11,7 +11,7 @@ import { z } from 'zod' export type AddressOrNfdFieldSchema = z.infer export type OptionalAddressOrNfdFieldSchema = z.infer -export type OptionalSenderFieldSchema = z.infer +export type OptionalSenderFieldSchema = z.infer export interface AddressFieldProps = Record> extends Omit, 'children'> { diff --git a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx index 1f62a8b4..39927163 100644 --- a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx @@ -1,10 +1,5 @@ import { numberSchema } from '@/features/forms/data/common' -import { - addressFieldSchema, - commonSchema, - optionalAddressFieldSchema, - optionalSenderFieldShape, -} from '@/features/transaction-wizard/data/common' +import { addressFieldSchema, commonSchema, optionalAddressFieldSchema } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -20,7 +15,7 @@ import { TransactionBuilderMode } from '../data' import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asOptionalAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' @@ -31,7 +26,7 @@ const closeRemainderToLabel = 'Close remainder to' const formSchema = z .object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, closeRemainderTo: addressFieldSchema, receiver: optionalAddressFieldSchema, amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0).optional()), @@ -71,7 +66,7 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAccoun type: BuildableTransactionType.AccountClose, sender: await resolveSenderAddress(data.sender), closeRemainderTo: data.closeRemainderTo, - receiver: asAddressOrNfd(data.receiver.value!), + receiver: asOptionalAddressOrNfd(data.receiver), amount: data.amount, fee: data.fee, validRounds: data.validRounds, @@ -83,7 +78,7 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAccoun const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, closeRemainderTo: transaction.closeRemainderTo, receiver: transaction.receiver, amount: transaction.amount, diff --git a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx index 1d8aa446..06215857 100644 --- a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx @@ -1,6 +1,11 @@ import algosdk from 'algosdk' import { bigIntSchema, numberSchema } from '@/features/forms/data/common' -import { commonSchema, onCompleteFieldSchema, onCompleteOptions, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' +import { + commonSchema, + onCompleteFieldSchema, + onCompleteOptions, + optionalAddressFieldSchema, +} from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' import { Form } from '@/features/forms/components/form' @@ -14,13 +19,13 @@ import { BuildAppCallTransactionResult, BuildableTransactionType } from '../mode import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...onCompleteFieldSchema, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), extraProgramPages: numberSchema(z.number().min(0).max(3).optional()), @@ -64,7 +69,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de if (mode === TransactionBuilderMode.Edit && transaction) { return { applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, onComplete: transaction.onComplete.toString(), extraProgramPages: transaction.extraProgramPages, fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx index 3636405f..250f6431 100644 --- a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx @@ -4,7 +4,7 @@ import { commonSchema, onCompleteOptionsForAppCreate, onCompleteForAppCreateFieldSchema, - optionalSenderFieldShape, + optionalAddressFieldSchema, } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' @@ -19,13 +19,13 @@ import { BuildApplicationCreateTransactionResult, BuildableTransactionType } fro import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...onCompleteForAppCreateFieldSchema, approvalProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), clearStateProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), @@ -79,7 +79,7 @@ export function ApplicationCreateTransactionBuilder({ mode, transaction, activeA return { approvalProgram: transaction.approvalProgram, clearStateProgram: transaction.clearStateProgram, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, onComplete: transaction.onComplete.toString(), extraProgramPages: transaction.extraProgramPages, globalInts: transaction.globalInts, diff --git a/src/features/transaction-wizard/components/application-update-transaction-builder.tsx b/src/features/transaction-wizard/components/application-update-transaction-builder.tsx index 21f7c364..ab34b0b3 100644 --- a/src/features/transaction-wizard/components/application-update-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/application-update-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, optionalSenderFieldShape } from '@/features/transaction-wizard/data/common' +import { commonSchema, optionalAddressFieldSchema } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' import { Form } from '@/features/forms/components/form' @@ -13,13 +13,13 @@ import { BuildApplicationUpdateTransactionResult, BuildableTransactionType } fro import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' const formData = zfd.formData({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), approvalProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), clearStateProgram: zfd.text(z.string({ required_error: 'Required', invalid_type_error: 'Required' })), @@ -64,7 +64,7 @@ export function ApplicationUpdateTransactionBuilder({ mode, transaction, activeA applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, approvalProgram: transaction.approvalProgram, clearStateProgram: transaction.clearStateProgram, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, diff --git a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx index 23ffdf8d..9825a9ce 100644 --- a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, decimalSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' +import { addressFieldSchema, commonSchema, optionalAddressFieldSchema, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,7 +21,7 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import resolveSenderAddress from '../utils/resolve-sender-address' const clawbackTargetLabel = 'Clawback target' @@ -29,7 +29,7 @@ const clawbackTargetLabel = 'Clawback target' export const assetClawbackFormSchema = z .object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...receiverFieldSchema, clawbackTarget: addressFieldSchema, asset: z @@ -202,7 +202,7 @@ export function AssetClawbackTransactionBuilder({ mode, transaction, onSubmit, o if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, receiver: transaction.receiver, clawbackTarget: transaction.clawbackTarget, amount: transaction.amount, diff --git a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx index d8f43542..de41f6ac 100644 --- a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, numberSchema } from '@/features/forms/data/common' -import { commonSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '../data/common' +import { commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -15,13 +15,13 @@ import { FormFieldHelper } from '@/features/forms/components/form-field-helper' import { ZERO_ADDRESS } from '@/features/common/constants' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetCreateFormSchema = z.object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, total: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).gt(BigInt(0), 'Must be greater than 0')), decimals: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0).max(19)), assetName: zfd.text(z.string().optional()), @@ -156,7 +156,7 @@ export function AssetCreateTransactionBuilder({ mode, transaction, activeAccount unitName: transaction.unitName, total: transaction.total, decimals: transaction.decimals, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, manager: transaction.manager, reserve: transaction.reserve, freeze: transaction.freeze, diff --git a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx index 594bbb3c..fdc0b0f0 100644 --- a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, optionalSenderFieldShape } from '../data/common' +import { commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -24,12 +24,12 @@ import { ellipseAddress } from '@/utils/ellipse-address' import { cn } from '@/features/common/utils' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetDestroyFormSchema = z.object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -178,7 +178,7 @@ export function AssetDestroyTransactionBuilder({ mode, transaction, onSubmit, on if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, diff --git a/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx index da7c8852..3f74e99e 100644 --- a/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-freeze-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, optionalSenderFieldShape } from '../data/common' +import { addressFieldSchema, commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -22,13 +22,13 @@ import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' import { freezeAssetLabel, unfreezeAssetLabel } from '../mappers' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetFreezeFormSchema = z .object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, freezeTarget: addressFieldSchema, frozen: z.union([z.string(), z.boolean()]), asset: z @@ -197,7 +197,7 @@ export function AssetFreezeTransactionBuilder({ mode, transaction, onSubmit, onC if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, freezeTarget: transaction.freezeTarget, frozen: transaction.frozen ? 'true' : 'false', fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx index 7712aefc..4075fb8b 100644 --- a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, optionalSenderFieldShape } from '../data/common' +import { commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,13 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetOptInFormSchema = z.object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -156,7 +156,7 @@ export function AssetOptInTransactionBuilder({ mode, transaction, activeAccount, if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, fee: transaction.fee, validRounds: transaction.validRounds, note: transaction.note, diff --git a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx index 19ef4702..09405af3 100644 --- a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { addressFieldSchema, commonSchema, optionalSenderFieldShape } from '../data/common' +import { addressFieldSchema, commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,13 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetOptOutFormSchema = z.object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, closeRemainderTo: addressFieldSchema, asset: z .object({ @@ -164,7 +164,7 @@ export function AssetOptOutTransactionBuilder({ mode, transaction, activeAccount if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, closeRemainderTo: transaction.closeRemainderTo, fee: transaction.fee, validRounds: transaction.validRounds, diff --git a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx index efaec0dc..9939ba39 100644 --- a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema } from '@/features/forms/data/common' -import { commonSchema, optionalAddressFieldSchema, optionalSenderFieldShape } from '../data/common' +import { commonSchema, optionalAddressFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,13 +21,13 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetReconfigureFormSchema = z .object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, asset: z .object({ id: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' }).min(1n)), @@ -233,7 +233,7 @@ export function AssetReconfigureTransactionBuilder({ mode, transaction, onSubmit if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, manager: transaction.manager, reserve: transaction.reserve, freeze: transaction.freeze, diff --git a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx index f66ca996..eb061ff0 100644 --- a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx @@ -1,5 +1,5 @@ import { bigIntSchema, decimalSchema } from '@/features/forms/data/common' -import { commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' +import { commonSchema, optionalAddressFieldSchema, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo, useState } from 'react' import { zfd } from 'zod-form-data' @@ -21,7 +21,7 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' @@ -29,7 +29,7 @@ const receiverLabel = 'Receiver' export const assetTransferFormSchema = z.object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...receiverFieldSchema, asset: z .object({ @@ -176,7 +176,7 @@ export function AssetTransferTransactionBuilder({ mode, transaction, activeAccou if (mode === TransactionBuilderMode.Edit && transaction) { return { asset: transaction.asset, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, receiver: transaction.receiver, amount: transaction.amount, fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx b/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx index 88bbd021..25a52f6b 100644 --- a/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/key-registration-transaction-builder.tsx @@ -1,4 +1,4 @@ -import { commonSchema, optionalSenderFieldShape, requiredMessage } from '../data/common' +import { commonSchema, optionalAddressFieldSchema, requiredMessage } from '../data/common' import { z } from 'zod' import { useCallback, useEffect, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -17,14 +17,14 @@ import { FormFieldHelper } from '@/features/forms/components/form-field-helper' import { useFormContext } from 'react-hook-form' import { bigIntSchema } from '@/features/forms/data/common' import { offlineKeyRegistrationLabel, onlineKeyRegistrationLabel } from '../mappers' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' export const keyRegistrationFormSchema = z .object({ ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, online: z.string(), voteKey: z.string().optional(), selectionKey: z.string().optional(), @@ -203,7 +203,7 @@ export function KeyRegistrationTransactionBuilder({ mode, transaction, activeAcc const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, online: transaction.online ? 'true' : 'false', voteKey: transaction.voteKey, selectionKey: transaction.selectionKey, diff --git a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx index 012dd33d..a2032f90 100644 --- a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx @@ -4,7 +4,7 @@ import { commonSchema, onCompleteFieldSchema, onCompleteOptions as _onCompleteOptions, - optionalSenderFieldShape, + optionalAddressFieldSchema, } from '@/features/transaction-wizard/data/common' import { z } from 'zod' import { zfd } from 'zod-form-data' @@ -36,14 +36,14 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/features/common/compo import { Info } from 'lucide-react' import { ApplicationId } from '@/features/applications/data/types' import { MethodDefinition } from '@/features/applications/models' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import { AbiFormItemValue } from '@/features/abi-methods/models' import resolveSenderAddress from '../utils/resolve-sender-address' const appCallFormSchema = { ...commonSchema, - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...onCompleteFieldSchema, applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })), methodName: zfd.text(), @@ -188,7 +188,7 @@ export function MethodCallTransactionBuilder({ ) return { applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined, - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, onComplete: transaction.onComplete.toString(), methodName: transaction.methodDefinition.name, extraProgramPages: transaction.extraProgramPages, diff --git a/src/features/transaction-wizard/components/payment-transaction-builder.tsx b/src/features/transaction-wizard/components/payment-transaction-builder.tsx index dd9c5e72..c5eb9485 100644 --- a/src/features/transaction-wizard/components/payment-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/payment-transaction-builder.tsx @@ -1,5 +1,5 @@ import { numberSchema } from '@/features/forms/data/common' -import { commonSchema, optionalSenderFieldShape, receiverFieldSchema } from '../data/common' +import { commonSchema, optionalAddressFieldSchema, receiverFieldSchema } from '../data/common' import { z } from 'zod' import { useCallback, useMemo } from 'react' import { zfd } from 'zod-form-data' @@ -15,14 +15,14 @@ import { TransactionBuilderMode } from '../data' import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asTransactionSender } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' const receiverLabel = 'Receiver' export const paymentFormSchema = z.object({ - ...optionalSenderFieldShape, + sender: optionalAddressFieldSchema, ...commonSchema, ...receiverFieldSchema, amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0)), @@ -56,7 +56,7 @@ export function PaymentTransactionBuilder({ mode, transaction, activeAccount, on const defaultValues = useMemo>>(() => { if (mode === TransactionBuilderMode.Edit && transaction) { return { - sender: asTransactionSender(transaction.sender), + sender: transaction.sender?.autoPopulated ? undefined : transaction.sender, receiver: transaction.receiver, amount: transaction.amount, fee: transaction.fee, diff --git a/src/features/transaction-wizard/components/transactions-builder.tsx b/src/features/transaction-wizard/components/transactions-builder.tsx index f8b72d7f..955b721a 100644 --- a/src/features/transaction-wizard/components/transactions-builder.tsx +++ b/src/features/transaction-wizard/components/transactions-builder.tsx @@ -329,7 +329,6 @@ export function TransactionsBuilder({ }, [activeAddress, commonButtonDisableProps, requireSignaturesOnSimulate]) const sendButtonDisabledProps = useMemo(() => { - // derive it, don't store it const hasAutoPopulatedSender = transactions.some((t) => t.sender?.autoPopulated === true) if (hasAutoPopulatedSender) { diff --git a/src/features/transaction-wizard/data/common.ts b/src/features/transaction-wizard/data/common.ts index 5c714975..b998d2e8 100644 --- a/src/features/transaction-wizard/data/common.ts +++ b/src/features/transaction-wizard/data/common.ts @@ -50,11 +50,6 @@ export const optionalAddressFieldSchema = z export const senderFieldSchema = { sender: addressFieldSchema } -// TODO Arthur - Added this shape to make the sender optional in the forms that required it -export const optionalSenderFieldShape = { - sender: optionalAddressFieldSchema, -} as const - export const receiverFieldSchema = { receiver: addressFieldSchema } export const noteFieldSchema = { note: zfd.text(z.string().optional()) } diff --git a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts index a6cced05..d4c5a463 100644 --- a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts +++ b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts @@ -18,8 +18,8 @@ export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): export const asTransactionSender = (transactionSender?: TransactionSender): TransactionSender => { const emptySender: TransactionSender = { - value: undefined, - resolvedAddress: undefined, + value: '', + resolvedAddress: '', autoPopulated: false, } if (!transactionSender) return emptySender @@ -30,6 +30,11 @@ export const asTransactionSender = (transactionSender?: TransactionSender): Tran : emptySender } +export const asOptionalAddressOrNfd = (addressOrNfdSchema: Partial) => { + return addressOrNfdSchema.value && addressOrNfdSchema.resolvedAddress + ? ({ value: addressOrNfdSchema.value, resolvedAddress: addressOrNfdSchema.resolvedAddress } satisfies AddressOrNfd) + : undefined +} export const asOptionalAddressOrNfdSchema = (address?: Address) => { return { value: address, diff --git a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts index 14f4c049..556aa1bc 100644 --- a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts +++ b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts @@ -86,7 +86,7 @@ export const asPaymentTransactionParams = ( transaction: BuildPaymentTransactionResult | BuildAccountCloseTransactionResult ): PaymentParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, receiver: transaction.receiver ? transaction.receiver.resolvedAddress : (transaction.sender?.resolvedAddress ?? 'LOL IDK'), closeRemainderTo: 'closeRemainderTo' in transaction ? transaction.closeRemainderTo.resolvedAddress : undefined, amount: algos(transaction.amount ?? 0), diff --git a/src/features/transaction-wizard/mappers/as-description-list-items.tsx b/src/features/transaction-wizard/mappers/as-description-list-items.tsx index 72a6ab05..5f070952 100644 --- a/src/features/transaction-wizard/mappers/as-description-list-items.tsx +++ b/src/features/transaction-wizard/mappers/as-description-list-items.tsx @@ -102,7 +102,7 @@ const asPaymentTransaction = (txn: BuildPaymentTransactionResult | BuildAccountC return [ { dt: 'Sender', - dd: , + dd: , }, ...('closeRemainderTo' in params && params.closeRemainderTo ? [ diff --git a/src/features/transaction-wizard/models/index.ts b/src/features/transaction-wizard/models/index.ts index dcfd882c..8e4185fe 100644 --- a/src/features/transaction-wizard/models/index.ts +++ b/src/features/transaction-wizard/models/index.ts @@ -66,8 +66,8 @@ export type AddressOrNfd = { } export type TransactionSender = { - value: Address | Nfd | undefined - resolvedAddress: Address | undefined + value: Address | Nfd + resolvedAddress: Address autoPopulated?: boolean } diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 2bbe9724..0dbea7be 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -60,7 +60,8 @@ export function TransactionWizardPage() {

Create and send transactions to the selected network using a connected wallet.

t.id).join('|')} // rerender when it gets populated + defaultTransactions={searchParamsTransactions.transactions} title={

{transactionGroupLabel}

} onSendTransactions={sendTransactions} onSimulated={renderSimulateResult} diff --git a/src/features/transaction-wizard/utils/resolve-sender-address.ts b/src/features/transaction-wizard/utils/resolve-sender-address.ts index b70a1930..260bff28 100644 --- a/src/features/transaction-wizard/utils/resolve-sender-address.ts +++ b/src/features/transaction-wizard/utils/resolve-sender-address.ts @@ -6,14 +6,12 @@ import { BETANET_FEE_SINK_ADDRESS, FNET_FEE_SINK_ADDRESS, } from '@/features/network/data' -import { AddressOrNfd, TransactionSender } from '../models' +import { TransactionSender } from '../models' import { settingsStore } from '@/features/settings/data' import { betanetId, mainnetId, testnetId, fnetId, localnetId } from '@/features/network/data' import { algorandClient } from '@/features/common/data/algo-client' -export default async function resolveSenderAddress( - data: T -): Promise { +export default async function resolveSenderAddress(data: OptionalSenderFieldSchema): Promise { const { id: networkId } = settingsStore.get(networkConfigAtom) const val = data?.value ?? '' diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index d7d4050e..e6f6294b 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -38,7 +38,7 @@ describe('Render transactions page with search params', () => { describe('key registration search params', () => { beforeEach(() => {}) - it('should render offline key registration', () => { + it('should render offline key registration', async () => { const sender = 'I3345FUQQ2GRBHFZQPLYQQX5HJMMRZMABCHRLWV6RCJYC6OO4MOLEUBEGU' renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ @@ -46,11 +46,11 @@ describe('Render transactions page with search params', () => { 'sender[0]': sender, }), }) - expect(screen.getByText('Offline')).toBeInTheDocument() - expect(screen.getByText(sender)).toBeInTheDocument() + expect(await screen.findByText('Offline')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() }) - it('should render online key registration with url safe values', () => { + it('should render online key registration with url safe values', async () => { const sender = 'I3345FUQQ2GRBHFZQPLYQQX5HJMMRZMABCHRLWV6RCJYC6OO4MOLEUBEGU' const selkey = '-lfw-Y04lTnllJfncgMjXuAePe8i8YyVeoR9c1Xi78c' const sprfkey = '3NoXc2sEWlvQZ7XIrwVJjgjM30ndhvwGgcqwKugk1u5W_iy_JITXrykuy0hUvAxbVv0njOgBPtGFsFif3yLJpg' @@ -72,20 +72,20 @@ describe('Render transactions page with search params', () => { 'fee[0]': fee.toString(), }), }) - expect(screen.getByText('Online')).toBeInTheDocument() - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText('+lfw+Y04lTnllJfncgMjXuAePe8i8YyVeoR9c1Xi78c=')).toBeInTheDocument() + expect(await screen.findByText('Online')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText('+lfw+Y04lTnllJfncgMjXuAePe8i8YyVeoR9c1Xi78c=')).toBeInTheDocument() expect( - screen.getByText('3NoXc2sEWlvQZ7XIrwVJjgjM30ndhvwGgcqwKugk1u5W/iy/JITXrykuy0hUvAxbVv0njOgBPtGFsFif3yLJpg==') + await screen.findByText('3NoXc2sEWlvQZ7XIrwVJjgjM30ndhvwGgcqwKugk1u5W/iy/JITXrykuy0hUvAxbVv0njOgBPtGFsFif3yLJpg==') ).toBeInTheDocument() - expect(screen.getByText(votefst.toString())).toBeInTheDocument() - expect(screen.getByText(votekd.toString())).toBeInTheDocument() - expect(screen.getByText('UU8zLMrFVfZPnzbnL6ThAArXFsznV3TvFVAun2ONcEI=')).toBeInTheDocument() - expect(screen.getByText(votelst.toString())).toBeInTheDocument() - expect(screen.getByText('2')).toBeInTheDocument() + expect(await screen.findByText(votefst.toString())).toBeInTheDocument() + expect(await screen.findByText(votekd.toString())).toBeInTheDocument() + expect(await screen.findByText('UU8zLMrFVfZPnzbnL6ThAArXFsznV3TvFVAun2ONcEI=')).toBeInTheDocument() + expect(await screen.findByText(votelst.toString())).toBeInTheDocument() + expect(await screen.findByText('2')).toBeInTheDocument() }) - it('should render online key registration with url encoded values', () => { + it('should render online key registration with url encoded values', async () => { const sender = 'I3345FUQQ2GRBHFZQPLYQQX5HJMMRZMABCHRLWV6RCJYC6OO4MOLEUBEGU' const selkey = '+lfw+Y04lTnllJfncgMjXuAePe8i8YyVeoR9c1Xi78c=' const sprfkey = '3NoXc2sEWlvQZ7XIrwVJjgjM30ndhvwGgcqwKugk1u5W/iy/JITXrykuy0hUvAxbVv0njOgBPtGFsFif3yLJpg==' @@ -107,15 +107,15 @@ describe('Render transactions page with search params', () => { 'fee[0]': fee.toString(), }), }) - expect(screen.getByText('Online')).toBeInTheDocument() - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(selkey)).toBeInTheDocument() - expect(screen.getByText(sprfkey)).toBeInTheDocument() - expect(screen.getByText(votefst.toString())).toBeInTheDocument() - expect(screen.getByText(votekd.toString())).toBeInTheDocument() - expect(screen.getByText(votekey)).toBeInTheDocument() - expect(screen.getByText(votelst.toString())).toBeInTheDocument() - expect(screen.getByText('2')).toBeInTheDocument() + expect(await screen.findByText('Online')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(selkey)).toBeInTheDocument() + expect(await screen.findByText(sprfkey)).toBeInTheDocument() + expect(await screen.findByText(votefst.toString())).toBeInTheDocument() + expect(await screen.findByText(votekd.toString())).toBeInTheDocument() + expect(await screen.findByText(votekey)).toBeInTheDocument() + expect(await screen.findByText(votelst.toString())).toBeInTheDocument() + expect(await screen.findByText('2')).toBeInTheDocument() }) }) @@ -126,7 +126,7 @@ describe('Render transactions page with search params', () => { const fee = 3_000_000 const note = 'Some payment notes' - it('should render payment transaction with minimal required fields only', () => { + it('should render payment transaction with minimal required fields only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'pay', @@ -136,12 +136,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText('2.5')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText('2.5')).toBeInTheDocument() }) - it('should render payment transaction with all optional fields', () => { + it('should render payment transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'pay', @@ -152,14 +152,14 @@ describe('Render transactions page with search params', () => { 'note[0]': note, }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText('2.5')).toBeInTheDocument() - expect(screen.getByText('3')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText('2.5')).toBeInTheDocument() + expect(await screen.findByText('3')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render payment transaction with fee only', () => { + it('should render payment transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'pay', @@ -169,13 +169,13 @@ describe('Render transactions page with search params', () => { 'fee[0]': fee.toString(), }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText('2.5')).toBeInTheDocument() - expect(screen.getByText('3')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText('2.5')).toBeInTheDocument() + expect(await screen.findByText('3')).toBeInTheDocument() }) - it('should render payment transaction with note only', () => { + it('should render payment transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'pay', @@ -185,10 +185,10 @@ describe('Render transactions page with search params', () => { 'note[0]': note, }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText('2.5')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText('2.5')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) it.each([ @@ -270,7 +270,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset creation test' - it('should render asset create transaction with minimal required fields only', () => { + it('should render asset create transaction with minimal required fields only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'acfg', @@ -280,12 +280,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText('1000000')).toBeInTheDocument() - expect(screen.getByText(decimals)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText('1000000')).toBeInTheDocument() + expect(await screen.findByText(decimals)).toBeInTheDocument() }) - it('should render asset create transaction with all optional fields', () => { + it('should render asset create transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'acfg', @@ -306,21 +306,21 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText('1000000')).toBeInTheDocument() - expect(screen.getByText(decimals)).toBeInTheDocument() - expect(screen.getByText(assetName)).toBeInTheDocument() - expect(screen.getByText(unitName)).toBeInTheDocument() - expect(screen.getByText(url)).toBeInTheDocument() - expect(screen.getByText(manager)).toBeInTheDocument() - expect(screen.getByText(reserve)).toBeInTheDocument() - expect(screen.getByText(freeze)).toBeInTheDocument() - expect(screen.getByText(clawback)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() - }) - - it('should render asset create transaction with fee only', () => { + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText('1000000')).toBeInTheDocument() + expect(await screen.findByText(decimals)).toBeInTheDocument() + expect(await screen.findByText(assetName)).toBeInTheDocument() + expect(await screen.findByText(unitName)).toBeInTheDocument() + expect(await screen.findByText(url)).toBeInTheDocument() + expect(await screen.findByText(manager)).toBeInTheDocument() + expect(await screen.findByText(reserve)).toBeInTheDocument() + expect(await screen.findByText(freeze)).toBeInTheDocument() + expect(await screen.findByText(clawback)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() + }) + + it('should render asset create transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'acfg', @@ -331,13 +331,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText('1000000')).toBeInTheDocument() - expect(screen.getByText(decimals)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText('1000000')).toBeInTheDocument() + expect(await screen.findByText(decimals)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset create transaction with note only', () => { + it('should render asset create transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'acfg', @@ -348,10 +348,10 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText('1000000')).toBeInTheDocument() - expect(screen.getByText(decimals)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText('1000000')).toBeInTheDocument() + expect(await screen.findByText(decimals)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) it.each([ @@ -463,7 +463,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset opt-in test' - it('should render asset opt-in transaction with minimal required fields', () => { + it('should render asset opt-in transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'axfer', @@ -474,11 +474,11 @@ describe('Render transactions page with search params', () => { }) // Sender is displayed twice in the UI, once as the sender and once as the asset receiver. - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() }) - it('should render asset opt-in transaction with all optional fields', () => { + it('should render asset opt-in transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'axfer', @@ -492,14 +492,14 @@ describe('Render transactions page with search params', () => { }) screen.debug(undefined, 1000000) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`0 ${unitName}`)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset opt-in transaction with fee only', () => { + it('should render asset opt-in transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'axfer', @@ -510,12 +510,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset opt-in transaction with note only', () => { + it('should render asset opt-in transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'axfer', @@ -526,12 +526,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset opt-in transaction with unit name only', () => { + it('should render asset opt-in transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'axfer', @@ -542,9 +542,9 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`0 ${unitName}`)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() }) it.each([ @@ -635,7 +635,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset opt-out test' - it('should render asset opt-out transaction with minimal required fields', () => { + it('should render asset opt-out transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetOptOut', @@ -646,12 +646,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(closeto)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() }) - it('should render asset opt-out transaction with all optional fields', () => { + it('should render asset opt-out transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetOptOut', @@ -665,15 +665,15 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(closeto)).toBeInTheDocument() - expect(screen.getByText(`0 ${unitName}`)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() + expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset opt-out transaction with fee only', () => { + it('should render asset opt-out transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetOptOut', @@ -685,13 +685,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(closeto)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset opt-out transaction with note only', () => { + it('should render asset opt-out transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetOptOut', @@ -703,13 +703,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(closeto)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset opt-out transaction with unit name only', () => { + it('should render asset opt-out transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetOptOut', @@ -721,10 +721,10 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getAllByText(sender)).toHaveLength(2) - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(closeto)).toBeInTheDocument() - expect(screen.getByText(`0 ${unitName}`)).toBeInTheDocument() + expect(await screen.findAllByText(sender)).toHaveLength(2) + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() + expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() }) it.each([ @@ -830,7 +830,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset transfer test' - it('should render asset transfer transaction with minimal required fields', () => { + it('should render asset transfer transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetTransfer', @@ -842,13 +842,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() }) - it('should render asset transfer transaction with all optional fields', () => { + it('should render asset transfer transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetTransfer', @@ -864,15 +864,15 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`${amount} ${unitName}`)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`${amount} ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset transfer transaction with fee only', () => { + it('should render asset transfer transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetTransfer', @@ -885,14 +885,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset transfer transaction with note only', () => { + it('should render asset transfer transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetTransfer', @@ -905,14 +905,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset transfer transaction with unit name only', () => { + it('should render asset transfer transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetTransfer', @@ -925,10 +925,10 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`${amount} ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`${amount} ${unitName}`)).toBeInTheDocument() }) it.each([ @@ -1055,7 +1055,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset reconfigure test' - it('should render asset reconfigure transaction with minimal required fields', () => { + it('should render asset reconfigure transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetReconfigure', @@ -1066,11 +1066,11 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) - it('should render asset reconfigure transaction with all optional fields', () => { + it('should render asset reconfigure transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetReconfigure', @@ -1088,17 +1088,17 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(manager)).toBeInTheDocument() - expect(screen.getByText(reserve)).toBeInTheDocument() - expect(screen.getByText(freeze)).toBeInTheDocument() - expect(screen.getByText(clawback)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(manager)).toBeInTheDocument() + expect(await screen.findByText(reserve)).toBeInTheDocument() + expect(await screen.findByText(freeze)).toBeInTheDocument() + expect(await screen.findByText(clawback)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset reconfigure transaction with fee only', () => { + it('should render asset reconfigure transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetReconfigure', @@ -1110,12 +1110,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset reconfigure transaction with note only', () => { + it('should render asset reconfigure transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetReconfigure', @@ -1127,12 +1127,12 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset reconfigure transaction with unit name only', () => { + it('should render asset reconfigure transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetReconfigure', @@ -1144,8 +1144,8 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) it.each([ @@ -1296,7 +1296,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset destroy test' - it('should render asset destroy transaction with minimal required fields', () => { + it('should render asset destroy transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetDestroy', @@ -1307,11 +1307,11 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) - it('should render asset destroy transaction with all optional fields', () => { + it('should render asset destroy transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetDestroy', @@ -1324,11 +1324,11 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) - it('should render asset destroy transaction with fee only', () => { + it('should render asset destroy transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetDestroy', @@ -1340,11 +1340,11 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) - it('should render asset destroy transaction with note only', () => { + it('should render asset destroy transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetDestroy', @@ -1356,8 +1356,8 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() }) it.each([ @@ -1472,7 +1472,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset freeze test' - it('should render asset freeze transaction with minimal required fields', () => { + it('should render asset freeze transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1485,13 +1485,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Freeze asset')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Freeze asset')).toBeInTheDocument() }) - it('should render asset freeze transaction with all optional fields', () => { + it('should render asset freeze transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1507,15 +1507,15 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Freeze asset')).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Freeze asset')).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset unfreeze transaction', () => { + it('should render asset unfreeze transaction', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1528,13 +1528,13 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Unfreeze asset')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Unfreeze asset')).toBeInTheDocument() }) - it('should render asset freeze transaction with fee only', () => { + it('should render asset freeze transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1548,14 +1548,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Freeze asset')).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Freeze asset')).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset freeze transaction with note only', () => { + it('should render asset freeze transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1569,14 +1569,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Freeze asset')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Freeze asset')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset freeze transaction with unit name only', () => { + it('should render asset freeze transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetFreeze', @@ -1590,10 +1590,10 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(freezeto)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText('Freeze asset')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(freezeto)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText('Freeze asset')).toBeInTheDocument() }) it.each([ @@ -1743,7 +1743,7 @@ describe('Render transactions page with search params', () => { const fee = '2000' const note = 'Asset clawback test' - it('should render asset clawback transaction with minimal required fields', () => { + it('should render asset clawback transaction with minimal required fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1757,14 +1757,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() }) - it('should render asset clawback transaction with all optional fields', () => { + it('should render asset clawback transaction with all optional fields', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1781,16 +1781,16 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`${amount} ${unitName}`)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`${amount} ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset clawback transaction with fee only', () => { + it('should render asset clawback transaction with fee only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1805,15 +1805,15 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() - expect(screen.getByText('0.002')).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() + expect(await screen.findByText('0.002')).toBeInTheDocument() }) - it('should render asset clawback transaction with note only', () => { + it('should render asset clawback transaction with note only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1828,15 +1828,15 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() - expect(screen.getByText(note)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() }) - it('should render asset clawback transaction with unit name only', () => { + it('should render asset clawback transaction with unit name only', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1851,14 +1851,14 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(`${amount} ${unitName}`)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`${amount} ${unitName}`)).toBeInTheDocument() }) - it('should render asset clawback transaction with clawbacktarget parameter', () => { + it('should render asset clawback transaction with clawbacktarget parameter', async () => { renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ 'type[0]': 'AssetClawback', @@ -1872,11 +1872,11 @@ describe('Render transactions page with search params', () => { }), }) - expect(screen.getByText(sender)).toBeInTheDocument() - expect(screen.getByText(receiver)).toBeInTheDocument() - expect(screen.getByText(clawbackfrom)).toBeInTheDocument() - expect(screen.getByText(assetId)).toBeInTheDocument() - expect(screen.getByText(amount)).toBeInTheDocument() + expect(await screen.findByText(sender)).toBeInTheDocument() + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(clawbackfrom)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() }) it.each([ diff --git a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts index 29d7d80b..92ee7649 100644 --- a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts +++ b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts @@ -29,6 +29,7 @@ import algosdk from 'algosdk' import { microAlgo } from '@algorandfoundation/algokit-utils' import Decimal from 'decimal.js' import { asTransactionSender } from '../mappers/as-address-or-nfd' +import resolveSenderAddress from './resolve-sender-address' // This is a workaround to make the online field a boolean instead of a string. // A string type is used in the form schema because of the value of radio buttons cant be boolean @@ -55,10 +56,10 @@ const transformKeyRegistrationTransaction = (params: BaseSearchParamTransaction) }, }) -const transformPaymentTransaction = (params: BaseSearchParamTransaction): BuildPaymentTransactionResult => ({ +const transformPaymentTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.Payment, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), receiver: { value: params.receiver, @@ -352,7 +353,7 @@ const transformationConfigByTransactionType = { // TODO: Add other transaction types } -export function transformSearchParamsTransactions(searchParamTransactions: BaseSearchParamTransaction[]) { +export async function transformSearchParamsTransactions(searchParamTransactions: BaseSearchParamTransaction[]) { const transactionsFromSearchParams: BuildTransactionResult[] = [] const errors: string[] = [] for (const [index, searchParamTransaction] of searchParamTransactions.entries()) { @@ -362,7 +363,7 @@ export function transformSearchParamsTransactions(searchParamTransactions: BaseS } const { transform, schema } = transformationConfigByTransactionType[configKey as keyof typeof transformationConfigByTransactionType] try { - const transaction = transform(searchParamTransaction) + const transaction = await Promise.resolve(transform(searchParamTransaction)) schema.parse(transaction) transactionsFromSearchParams.push(transaction) } catch (error) { diff --git a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts index c585ed72..5df61b21 100644 --- a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts +++ b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts @@ -1,44 +1,57 @@ +import { useEffect, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' -import { transformSearchParamsTransactions } from './transform-search-params-transactions' -import { BaseSearchParamTransaction } from '../models' import { toast } from 'react-toastify' -import { useEffect } from 'react' +import { transformSearchParamsTransactions } from './transform-search-params-transactions' +import type { BaseSearchParamTransaction, BuildTransactionResult } from '../models' const transformSearchParams = (searchParams: URLSearchParams) => { const entries = Array.from(searchParams.entries()) - // Group params by their index - const groupedParams = entries.reduce((acc, [key, value]) => { + const grouped = entries.reduce((acc, [key, value]) => { const match = key.match(/^([^[]+)\[(\d+)\]$/) if (!match) return acc - const [, paramName, index] = match - const idx = parseInt(index) - - if (!acc[idx]) { - acc[idx] = { type: '' } - } - + const idx = parseInt(index, 10) + acc[idx] ??= { type: '' } // ensure slot exists; keep your original default acc[idx][paramName] = value return acc }, []) - // Filter out empty entries and convert to array - return groupedParams.filter((entry) => Object.keys(entry).length > 0) + return grouped.filter((entry) => Object.keys(entry).length > 0) } export function useTransactionSearchParamsBuilder() { const [searchParams] = useSearchParams() - const transformedParams = transformSearchParams(searchParams) - const { transactions, errors } = transformSearchParamsTransactions(transformedParams) + + // memoize the parsed params so effect only runs when params actually change + const transformedParams = useMemo( + () => transformSearchParams(searchParams), + // URLSearchParams is mutable; tie memoization to its string form + [searchParams] + ) + + const [transactions, setTransactions] = useState([]) + const [errors, setErrors] = useState([]) + const [loading, setLoading] = useState(false) useEffect(() => { - if (errors && errors.length > 0) { - for (const error of errors) { - toast.error(error) + let cancelled = false + ;(async () => { + setLoading(true) + try { + const { transactions, errors = [] } = await transformSearchParamsTransactions(transformedParams) + setTransactions(transactions) + setErrors(errors) + // show toasts once per change + if (errors.length) errors.forEach((e) => toast.error(e)) + } finally { + if (!cancelled) setLoading(false) } + })() + return () => { + cancelled = true } - }, [errors]) + }, [transformedParams]) - return transactions + return { transactions, errors, loading } } From 9b185fa7fa2d53bc1f5e4a396e6b7040d605e8b9 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Mon, 10 Nov 2025 22:57:42 -0800 Subject: [PATCH 05/18] test(optional_sender): add optional sender to url params test --- .../transactions-url-search-params.test.tsx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index e6f6294b..f6fbcab8 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -1,5 +1,5 @@ import { createMemoryRouter, RouterProvider } from 'react-router-dom' -import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi, vitest } from 'vitest' import { TransactionWizardPage } from '../transaction-wizard-page' import { render, screen, cleanup } from '@testing-library/react' import { algorandFixture } from '@algorandfoundation/algokit-utils/testing' @@ -191,6 +191,26 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(note)).toBeInTheDocument() }) + // Test is failing with "Can't get LocalNet dispenser account from non LocalNet network"" + it('should render payment transaction without sender - auto populate sender with localnet address', async () => { + const localnetAddress = localnet.context.testAccount.addr.toString() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'pay', + 'receiver[0]': receiver, + 'amount[0]': amount.toString(), + 'fee[0]': fee.toString(), + 'note[0]': note, + }), + }) + + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText('2.5')).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() + expect(await screen.findByText(localnetAddress)).toBeInTheDocument() + }) + it.each([ // Missing required field cases { @@ -1166,6 +1186,7 @@ describe('Render transactions page with search params', () => { mode: 'missing', expected: 'Error in transaction at index 0 in the following fields: asset-id', }, + // Invalid field value cases { key: 'assetid[0]', From 184dcb62f66cdc75d73ad2a376a12016a2a74e36 Mon Sep 17 00:00:00 2001 From: Hoang Dinh Date: Thu, 13 Nov 2025 15:50:45 +1000 Subject: [PATCH 06/18] chore: add DataProvider to txn wizard test --- .../transactions-url-search-params.test.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index f6fbcab8..e4195089 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -5,20 +5,28 @@ import { render, screen, cleanup } from '@testing-library/react' import { algorandFixture } from '@algorandfoundation/algokit-utils/testing' import { TooltipProvider } from '@/features/common/components/tooltip' import { ToastContainer } from 'react-toastify' +import { DataProvider } from '@/features/common/components/data-provider' +import { localnetId, defaultNetworkConfigs } from '@/features/network/data/' const renderTxnsWizardPageWithSearchParams = ({ searchParams }: { searchParams: URLSearchParams }) => { const urlSearchParams = new URLSearchParams(searchParams).toString() + const router = createMemoryRouter( [ { path: '/localnet/transaction-wizard', element: ( - <> + - + ), }, ], @@ -193,7 +201,7 @@ describe('Render transactions page with search params', () => { // Test is failing with "Can't get LocalNet dispenser account from non LocalNet network"" it('should render payment transaction without sender - auto populate sender with localnet address', async () => { - const localnetAddress = localnet.context.testAccount.addr.toString() + const localnetDispenderAccount = (await localnet.algorand.account.localNetDispenser()).addr.toString() renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ @@ -208,7 +216,7 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(receiver)).toBeInTheDocument() expect(await screen.findByText('2.5')).toBeInTheDocument() expect(await screen.findByText(note)).toBeInTheDocument() - expect(await screen.findByText(localnetAddress)).toBeInTheDocument() + expect(await screen.findByText(localnetDispenderAccount)).toBeInTheDocument() }) it.each([ From 589b1a723aee0669e9d6b96d08b9f47b04458db3 Mon Sep 17 00:00:00 2001 From: Hoang Dinh Date: Thu, 13 Nov 2025 15:52:57 +1000 Subject: [PATCH 07/18] chore: lint-fix --- .../utils/transactions-url-search-params.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index e4195089..22c184e0 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -1,5 +1,5 @@ import { createMemoryRouter, RouterProvider } from 'react-router-dom' -import { afterEach, beforeEach, describe, expect, it, vi, vitest } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest' import { TransactionWizardPage } from '../transaction-wizard-page' import { render, screen, cleanup } from '@testing-library/react' import { algorandFixture } from '@algorandfoundation/algokit-utils/testing' From da58f63dce09b15ef18bc3a6e4f9387dc14dfbfd Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 12:44:17 -0800 Subject: [PATCH 08/18] feat(transaction-wizard): auto-populate sender from localnet dispenser in URL params --- .../mappers/as-address-or-nfd.ts | 26 ++-- .../transaction-wizard-page.test.tsx | 42 ++----- .../transactions-url-search-params.test.tsx | 116 +++++++++++++++++- .../transform-search-params-transactions.ts | 43 ++++--- 4 files changed, 154 insertions(+), 73 deletions(-) diff --git a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts index d4c5a463..8b7a765d 100644 --- a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts +++ b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts @@ -1,5 +1,5 @@ import { Address } from '@/features/accounts/data/types' -import { AddressOrNfd, TransactionSender } from '../models' +import { AddressOrNfd } from '../models' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): AddressOrNfd => { @@ -16,25 +16,15 @@ export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): } satisfies AddressOrNfd } -export const asTransactionSender = (transactionSender?: TransactionSender): TransactionSender => { - const emptySender: TransactionSender = { - value: '', - resolvedAddress: '', - autoPopulated: false, - } - if (!transactionSender) return emptySender - if (transactionSender.autoPopulated) return emptySender - - return transactionSender.value && transactionSender.resolvedAddress - ? { value: transactionSender.value, resolvedAddress: transactionSender.resolvedAddress, autoPopulated: transactionSender.autoPopulated } - : emptySender +export const asOptionalAddressOrNfd = (addressOrNfdSchema?: Partial): AddressOrNfd | undefined => { + if (!addressOrNfdSchema) return undefined + if (!addressOrNfdSchema.value || !addressOrNfdSchema.resolvedAddress) return undefined + return { + value: addressOrNfdSchema.value, + resolvedAddress: addressOrNfdSchema.resolvedAddress, + } satisfies AddressOrNfd } -export const asOptionalAddressOrNfd = (addressOrNfdSchema: Partial) => { - return addressOrNfdSchema.value && addressOrNfdSchema.resolvedAddress - ? ({ value: addressOrNfdSchema.value, resolvedAddress: addressOrNfdSchema.resolvedAddress } satisfies AddressOrNfd) - : undefined -} export const asOptionalAddressOrNfdSchema = (address?: Address) => { return { value: address, diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index 91f6d09d..7de7b411 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -386,41 +386,25 @@ describe('transaction-wizard-page', () => { }) await user.click(addButton) - const sendButton = await waitFor(() => { - const sendButton = component.getByRole('button', { name: sendButtonLabel }) - expect(sendButton).not.toBeDisabled() - return sendButton! + await waitFor(() => { + const table = component.getByLabelText('transaction-group-table') + expect(table).toBeInTheDocument() + expect(component.queryByText('No transactions.')).not.toBeInTheDocument() }) - await user.click(sendButton) - const resultsDiv = await waitFor( - () => { - expect(component.queryByText('Required')).not.toBeInTheDocument() - return component.getByText(groupSendResultsLabel).parentElement! - }, - { timeout: 10_000 } - ) + const simulateButton = await waitFor(() => { + const simulateButton = component.getByRole('button', { name: 'Simulate' }) + expect(simulateButton).not.toBeDisabled() + return simulateButton! + }) - const transactionId = await waitFor( + await user.click(simulateButton) + await waitFor( () => { - const transactionLink = within(resultsDiv) - .getAllByRole('link') - .find((a) => a.getAttribute('href')?.startsWith('/localnet/transaction'))! - return transactionLink.getAttribute('href')!.split('/').pop()! + expect(component.queryByText(/error/i)).not.toBeInTheDocument() }, - { timeout: 10_000 } + { timeout: 5_000 } ) - - const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) - expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` - TransactionPayment { - "amount": 0n, - "closeAmount": 9999000n, - "closeRemainderTo": "${testAccount2.addr}", - "receiver": "${testAccount.addr}", - } - `) } ) }) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index 22c184e0..a900a69a 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -44,8 +44,6 @@ describe('Render transactions page with search params', () => { vitest.clearAllMocks() }) describe('key registration search params', () => { - beforeEach(() => {}) - it('should render offline key registration', async () => { const sender = 'I3345FUQQ2GRBHFZQPLYQQX5HJMMRZMABCHRLWV6RCJYC6OO4MOLEUBEGU' renderTxnsWizardPageWithSearchParams({ @@ -125,6 +123,21 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(votelst.toString())).toBeInTheDocument() expect(await screen.findByText('2')).toBeInTheDocument() }) + + it('should render key registration without sender - auto populate sender with localnet address', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'keyreg', + }), + }) + + expect(await screen.findByText('Offline')).toBeInTheDocument() + // Find the yellow sender link (auto-populated) + const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) + expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) + }) }) describe('payment transaction search params', () => { @@ -201,7 +214,7 @@ describe('Render transactions page with search params', () => { // Test is failing with "Can't get LocalNet dispenser account from non LocalNet network"" it('should render payment transaction without sender - auto populate sender with localnet address', async () => { - const localnetDispenderAccount = (await localnet.algorand.account.localNetDispenser()).addr.toString() + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() renderTxnsWizardPageWithSearchParams({ searchParams: new URLSearchParams({ @@ -216,7 +229,7 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(receiver)).toBeInTheDocument() expect(await screen.findByText('2.5')).toBeInTheDocument() expect(await screen.findByText(note)).toBeInTheDocument() - expect(await screen.findByText(localnetDispenderAccount)).toBeInTheDocument() + expect(await screen.findByText(localnetDispenderAccount.toString())).toBeInTheDocument() }) it.each([ @@ -382,6 +395,24 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(note)).toBeInTheDocument() }) + it('should render asset create transaction without sender - auto populate sender with localnet address', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'acfg', + 'total[0]': total, + 'decimals[0]': decimals, + 'note[0]': note, + }), + }) + + expect(await screen.findByText(total)).toBeInTheDocument() + expect(await screen.findByText(decimals)).toBeInTheDocument() + expect(await screen.findByText(note)).toBeInTheDocument() + expect(await screen.findByText(localnetDispenderAccount.addr.toString())).toBeInTheDocument() + }) + it.each([ // Missing required field cases @@ -575,6 +606,25 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() }) + it('should render asset opt-in transaction without sender auto-populated', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'axfer', + 'assetid[0]': assetId, + 'decimals[0]': decimals, + 'unitname[0]': unitName, + }), + }) + + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() + // Find the yellow sender link (auto-populated) + const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) + expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) + }) + it.each([ // Missing required field cases @@ -755,6 +805,25 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() }) + it('should render asset opt-out transaction without sender - auto populate sender with localnet address', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'AssetOptOut', + 'assetid[0]': assetId, + 'closeto[0]': closeto, + 'decimals[0]': decimals, + }), + }) + + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(closeto)).toBeInTheDocument() + // Find the yellow sender link (auto-populated) + const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) + expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) + }) + it.each([ // Missing required field cases @@ -959,6 +1028,27 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(`${amount} ${unitName}`)).toBeInTheDocument() }) + it('should render asset transfer transaction without sender - auto populate sender with localnet address', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'AssetTransfer', + 'receiver[0]': receiver, + 'assetid[0]': assetId, + 'amount[0]': amount, + 'decimals[0]': decimals, + }), + }) + + expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(amount)).toBeInTheDocument() + // Find the yellow sender link (auto-populated) + const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) + expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) + }) + it.each([ // Missing required field cases @@ -1389,6 +1479,24 @@ describe('Render transactions page with search params', () => { expect(await screen.findByText(assetId)).toBeInTheDocument() }) + it('should render asset destroy transaction without sender - auto populate sender with localnet address', async () => { + const localnetDispenderAccount = await localnet.algorand.account.localNetDispenser() + + renderTxnsWizardPageWithSearchParams({ + searchParams: new URLSearchParams({ + 'type[0]': 'AssetDestroy', + 'assetid[0]': assetId, + 'assetmanager[0]': assetManager, + 'decimals[0]': decimals, + }), + }) + + expect(await screen.findByText(assetId)).toBeInTheDocument() + // Find the yellow sender link (auto-populated) + const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) + expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) + }) + it.each([ // Missing required field cases diff --git a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts index 92ee7649..7b00face 100644 --- a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts +++ b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts @@ -28,7 +28,6 @@ import { randomGuid } from '@/utils/random-guid' import algosdk from 'algosdk' import { microAlgo } from '@algorandfoundation/algokit-utils' import Decimal from 'decimal.js' -import { asTransactionSender } from '../mappers/as-address-or-nfd' import resolveSenderAddress from './resolve-sender-address' // This is a workaround to make the online field a boolean instead of a string. @@ -37,10 +36,10 @@ const keyRegFormSchema = keyRegistrationFormSchema.innerType().extend({ online: z.boolean(), }) -const transformKeyRegistrationTransaction = (params: BaseSearchParamTransaction): BuildKeyRegistrationTransactionResult => ({ +const transformKeyRegistrationTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.KeyRegistration, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), online: Boolean(params.votekey), fee: params.fee ? { setAutomatically: false, value: microAlgo(Number(params.fee)).algo } : { setAutomatically: true }, voteKey: params.votekey, @@ -59,7 +58,7 @@ const transformKeyRegistrationTransaction = (params: BaseSearchParamTransaction) const transformPaymentTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.Payment, - sender: await resolveSenderAddress({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), receiver: { value: params.receiver, @@ -79,10 +78,10 @@ const defaultOptionalAddress = { value: '', resolvedAddress: '', } -const transformAssetCreateTransaction = (params: BaseSearchParamTransaction): BuildAssetCreateTransactionResult => ({ +const transformAssetCreateTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetCreate, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), total: BigInt(params.total), decimals: Number(params.decimals), @@ -124,10 +123,10 @@ const transformAssetCreateTransaction = (params: BaseSearchParamTransaction): Bu note: params.note, }) -const transformAssetOptInTransaction = (params: BaseSearchParamTransaction): BuildAssetOptInTransactionResult => ({ +const transformAssetOptInTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetOptIn, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), asset: { id: BigInt(params.assetid), @@ -143,16 +142,15 @@ const transformAssetOptInTransaction = (params: BaseSearchParamTransaction): Bui note: params.note, }) -const transformAssetOptOutTransaction = (params: BaseSearchParamTransaction): BuildAssetOptOutTransactionResult => ({ +const transformAssetOptOutTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetOptOut, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), asset: { id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, unitName: params.unitname, - clawback: params.clawback, }, closeRemainderTo: { value: params.closeto, @@ -167,10 +165,10 @@ const transformAssetOptOutTransaction = (params: BaseSearchParamTransaction): Bu note: params.note, }) -const transformAssetTransferTransaction = (params: BaseSearchParamTransaction): BuildAssetTransferTransactionResult => ({ +const transformAssetTransferTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetTransfer, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), receiver: { value: params.receiver, @@ -192,10 +190,12 @@ const transformAssetTransferTransaction = (params: BaseSearchParamTransaction): note: params.note, }) -const transformAssetReconfigureTransaction = (params: BaseSearchParamTransaction): BuildAssetReconfigureTransactionResult => ({ +const transformAssetReconfigureTransaction = async ( + params: BaseSearchParamTransaction +): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetReconfigure, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), asset: { id: BigInt(params.assetid), @@ -236,10 +236,10 @@ const transformAssetReconfigureTransaction = (params: BaseSearchParamTransaction note: params.note, }) -const transformAssetFreezeTransaction = (params: BaseSearchParamTransaction): BuildAssetFreezeTransactionResult => ({ +const transformAssetFreezeTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetFreeze, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), freezeTarget: { value: params.freezeto, @@ -261,10 +261,10 @@ const transformAssetFreezeTransaction = (params: BaseSearchParamTransaction): Bu note: params.note, }) -const transformAssetDestroyTransaction = (params: BaseSearchParamTransaction): BuildAssetDestroyTransactionResult => ({ +const transformAssetDestroyTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetDestroy, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), asset: { id: BigInt(params.assetid), @@ -280,10 +280,10 @@ const transformAssetDestroyTransaction = (params: BaseSearchParamTransaction): B note: params.note, }) -const transformAssetClawbackTransaction = (params: BaseSearchParamTransaction): BuildAssetClawbackTransactionResult => ({ +const transformAssetClawbackTransaction = async (params: BaseSearchParamTransaction): Promise => ({ id: randomGuid(), type: BuildableTransactionType.AssetClawback, - sender: asTransactionSender({ value: params.sender!, resolvedAddress: params.sender!, autoPopulated: false }), + sender: await resolveSenderAddress({ value: params.sender, resolvedAddress: params.sender }), receiver: { value: params.receiver, @@ -350,7 +350,6 @@ const transformationConfigByTransactionType = { transform: transformAssetClawbackTransaction, schema: assetClawbackFormSchema, }, - // TODO: Add other transaction types } export async function transformSearchParamsTransactions(searchParamTransactions: BaseSearchParamTransaction[]) { From 171524520ea6db569f1eca8e89e991612aa269fe Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 13:06:36 -0800 Subject: [PATCH 09/18] fix(search_params): fix two tests that were failing only on CI/CD --- .../utils/transactions-url-search-params.test.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index a900a69a..9917750a 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -1041,6 +1041,8 @@ describe('Render transactions page with search params', () => { }), }) + await screen.findByText(receiver, {}, { timeout: 3000 }) + expect(await screen.findByText(receiver)).toBeInTheDocument() expect(await screen.findByText(assetId)).toBeInTheDocument() expect(await screen.findByText(amount)).toBeInTheDocument() @@ -1491,6 +1493,9 @@ describe('Render transactions page with search params', () => { }), }) + + await screen.findByText(assetId, {}, { timeout: 3000 }) + expect(await screen.findByText(assetId)).toBeInTheDocument() // Find the yellow sender link (auto-populated) const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) From 80d3136c25421f12d95e0e9cb56aa79f6f7acb0f Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 13:19:06 -0800 Subject: [PATCH 10/18] fix(test): add racing condition to wait asset-opt out render before testing --- .../utils/transactions-url-search-params.test.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index 9917750a..5a2ee69e 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -817,7 +817,7 @@ describe('Render transactions page with search params', () => { }), }) - expect(await screen.findByText(assetId)).toBeInTheDocument() + expect(await screen.findByText(assetId, {}, { timeout: 3000 })).toBeInTheDocument() expect(await screen.findByText(closeto)).toBeInTheDocument() // Find the yellow sender link (auto-populated) const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) @@ -1042,7 +1042,7 @@ describe('Render transactions page with search params', () => { }) await screen.findByText(receiver, {}, { timeout: 3000 }) - + expect(await screen.findByText(receiver)).toBeInTheDocument() expect(await screen.findByText(assetId)).toBeInTheDocument() expect(await screen.findByText(amount)).toBeInTheDocument() @@ -1493,9 +1493,8 @@ describe('Render transactions page with search params', () => { }), }) - await screen.findByText(assetId, {}, { timeout: 3000 }) - + expect(await screen.findByText(assetId)).toBeInTheDocument() // Find the yellow sender link (auto-populated) const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) From 4733d6521991680c2cb9256b52bd7420c015a738 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 13:27:17 -0800 Subject: [PATCH 11/18] fix(test): add racing condition to wait render before testing --- .../utils/transactions-url-search-params.test.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index 5a2ee69e..d0fc275d 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -133,7 +133,7 @@ describe('Render transactions page with search params', () => { }), }) - expect(await screen.findByText('Offline')).toBeInTheDocument() + expect(await screen.findByText('Offline', {}, { timeout: 3000 })).toBeInTheDocument() // Find the yellow sender link (auto-populated) const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) expect(senderLinks.some((link) => link.className.includes('text-yellow-500'))).toBe(true) @@ -226,7 +226,7 @@ describe('Render transactions page with search params', () => { }), }) - expect(await screen.findByText(receiver)).toBeInTheDocument() + expect(await screen.findByText(receiver, {}, { timeout: 3000 })).toBeInTheDocument() expect(await screen.findByText('2.5')).toBeInTheDocument() expect(await screen.findByText(note)).toBeInTheDocument() expect(await screen.findByText(localnetDispenderAccount.toString())).toBeInTheDocument() @@ -407,7 +407,7 @@ describe('Render transactions page with search params', () => { }), }) - expect(await screen.findByText(total)).toBeInTheDocument() + expect(await screen.findByText(total, {}, { timeout: 3000 })).toBeInTheDocument() expect(await screen.findByText(decimals)).toBeInTheDocument() expect(await screen.findByText(note)).toBeInTheDocument() expect(await screen.findByText(localnetDispenderAccount.addr.toString())).toBeInTheDocument() From 629e5d27e1f703953be9c6928e25d0e31652f26c Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 13:36:02 -0800 Subject: [PATCH 12/18] fix(test): add racing condition to wait render before testing --- .../utils/transactions-url-search-params.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx index d0fc275d..b4cfaf18 100644 --- a/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx +++ b/src/features/transaction-wizard/utils/transactions-url-search-params.test.tsx @@ -618,7 +618,8 @@ describe('Render transactions page with search params', () => { }), }) - expect(await screen.findByText(assetId)).toBeInTheDocument() + // Wait for transaction to be parsed and rendered + expect(await screen.findByText(assetId, {}, { timeout: 3000 })).toBeInTheDocument() expect(await screen.findByText(`0 ${unitName}`)).toBeInTheDocument() // Find the yellow sender link (auto-populated) const senderLinks = await screen.findAllByText(localnetDispenderAccount.addr.toString()) From d94d38615d436b517ebed0011551ca9706db8935 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Thu, 13 Nov 2025 17:38:40 -0800 Subject: [PATCH 13/18] reafactor(non-null): remove non-null assertion from the transaction mappers --- .../mappers/as-algosdk-transactions.ts | 28 +++++++++---------- .../mappers/as-description-list-items.tsx | 16 +++++------ .../utils/resolve-sender-address.ts | 3 +- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts index 556aa1bc..22dff33e 100644 --- a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts +++ b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts @@ -123,7 +123,7 @@ export const asMethodCallParams = async (transaction: BuildMethodCallTransaction ) return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, appId: BigInt(transaction.applicationId), method: transaction.methodDefinition.abiMethod, args: args, @@ -158,7 +158,7 @@ const asMethodCallTransactions = async (transaction: BuildMethodCallTransactionR export const asAppCallTransactionParams = (transaction: BuildAppCallTransactionResult): AppCallParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, appId: BigInt(transaction.applicationId), args: transaction.args.map((arg) => base64ToBytes(arg)), onComplete: transaction.onComplete, @@ -181,7 +181,7 @@ const asAppCallTransaction = async (transaction: BuildAppCallTransactionResult): export const asApplicationCreateTransactionParams = (transaction: BuildApplicationCreateTransactionResult): AppCreateParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, args: transaction.args.map((arg) => base64ToBytes(arg)), onComplete: transaction.onComplete, approvalProgram: base64ToBytes(transaction.approvalProgram), @@ -206,7 +206,7 @@ const asApplicationCreateTransaction = async (transaction: BuildApplicationCreat export const asApplicationUpdateTransactionParams = (transaction: BuildApplicationUpdateTransactionResult): AppUpdateParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, appId: BigInt(transaction.applicationId), args: transaction.args.map((arg) => base64ToBytes(arg)), approvalProgram: base64ToBytes(transaction.approvalProgram), @@ -239,8 +239,8 @@ export const asAssetTransferTransactionParams = ( amount = BigInt(convertedAmount.toString()) } return { - sender: transaction.sender.resolvedAddress!, - receiver: 'receiver' in transaction ? transaction.receiver.resolvedAddress : transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, + receiver: 'receiver' in transaction ? transaction.receiver.resolvedAddress : transaction.sender.resolvedAddress, clawbackTarget: 'clawbackTarget' in transaction ? transaction.clawbackTarget.resolvedAddress : undefined, closeAssetTo: 'closeRemainderTo' in transaction ? transaction.closeRemainderTo.resolvedAddress : undefined, assetId: BigInt(transaction.asset.id), @@ -259,7 +259,7 @@ const asAssetTransferTransaction = async ( ): Promise => { if ( transaction.type === BuildableTransactionType.AssetClawback && - (!transaction.asset.clawback || transaction.sender.resolvedAddress! !== transaction.asset.clawback) + (!transaction.asset.clawback || transaction.sender.resolvedAddress !== transaction.asset.clawback) ) { throw new Error('Invalid clawback transaction') } @@ -270,7 +270,7 @@ const asAssetTransferTransaction = async ( export const asAssetCreateTransactionParams = (transaction: BuildAssetCreateTransactionResult): AssetCreateParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, total: transaction.total, decimals: transaction.decimals, assetName: transaction.assetName, @@ -294,7 +294,7 @@ const asAssetCreateTransaction = async (transaction: BuildAssetCreateTransaction const asAssetReconfigureTransactionParams = (transaction: BuildAssetReconfigureTransactionResult): AssetConfigParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, assetId: BigInt(transaction.asset.id), manager: transaction.manager ? transaction.manager.resolvedAddress : undefined, reserve: transaction.reserve ? transaction.reserve.resolvedAddress : undefined, @@ -312,7 +312,7 @@ const asAssetReconfigureTransaction = async (transaction: BuildAssetReconfigureT const asAssetDestroyTransactionParams = (transaction: BuildAssetDestroyTransactionResult): AssetDestroyParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, assetId: BigInt(transaction.asset.id), } } @@ -338,7 +338,7 @@ export const asAssetConfigTransactionParams = ( export const asAssetFreezeTransactionParams = (transaction: BuildAssetFreezeTransactionResult): AssetFreezeParams => { return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, assetId: BigInt(transaction.asset.id), account: transaction.freezeTarget.resolvedAddress, frozen: transaction.frozen, @@ -348,7 +348,7 @@ export const asAssetFreezeTransactionParams = (transaction: BuildAssetFreezeTran } } const asAssetFreezeTransaction = async (transaction: BuildAssetFreezeTransactionResult): Promise => { - if (!transaction.asset.freeze || transaction.sender.resolvedAddress! !== transaction.asset.freeze) { + if (!transaction.asset.freeze || transaction.sender.resolvedAddress !== transaction.asset.freeze) { throw new Error('Invalid freeze transaction') } @@ -365,7 +365,7 @@ export const asKeyRegistrationTransactionParams = ( invariant(transaction.stateProofKey, 'State proof key is required') return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, voteKey: Uint8Array.from(Buffer.from(transaction.voteKey, 'base64')), selectionKey: Uint8Array.from(Buffer.from(transaction.selectionKey, 'base64')), stateProofKey: Uint8Array.from(Buffer.from(transaction.stateProofKey, 'base64')), @@ -379,7 +379,7 @@ export const asKeyRegistrationTransactionParams = ( } return { - sender: transaction.sender.resolvedAddress!, + sender: transaction.sender.resolvedAddress, } } diff --git a/src/features/transaction-wizard/mappers/as-description-list-items.tsx b/src/features/transaction-wizard/mappers/as-description-list-items.tsx index 5f070952..427d5855 100644 --- a/src/features/transaction-wizard/mappers/as-description-list-items.tsx +++ b/src/features/transaction-wizard/mappers/as-description-list-items.tsx @@ -142,7 +142,7 @@ const asAssetTransferTransaction = ( }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Receiver', @@ -194,7 +194,7 @@ const asAssetConfigTransaction = ( ...('decimals' in params && params.decimals !== undefined ? [{ dt: 'Decimals', dd: params.decimals }] : []), { dt: transaction.type === BuildableTransactionType.AssetCreate ? 'Creator' : 'Sender', - dd: , + dd: , }, ...('manager' in params && params.manager ? [ @@ -249,7 +249,7 @@ const asAssetFreezeTransaction = (transaction: BuildAssetFreezeTransactionResult }, { dt: 'Sender', - dd: , + dd: , }, ...('account' in params && params.account ? [ @@ -275,7 +275,7 @@ const asKeyRegistrationTransaction = (transaction: BuildKeyRegistrationTransacti return [ { dt: 'Sender', - dd: , + dd: , }, { dt: 'Registration', @@ -387,7 +387,7 @@ const asAppCallTransaction = (transaction: BuildAppCallTransactionResult): Descr }, { dt: 'Sender', - dd: , + dd: , }, ...(transaction.extraProgramPages !== undefined ? [ @@ -440,7 +440,7 @@ const asMethodCallTransaction = ( }, { dt: 'Sender', - dd: , + dd: , }, ...(transaction.extraProgramPages !== undefined ? [ @@ -700,7 +700,7 @@ const asApplicationCreateTransaction = (transaction: BuildApplicationCreateTrans }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Approval program', @@ -763,7 +763,7 @@ const asApplicationUpdateTransaction = (transaction: BuildApplicationUpdateTrans }, { dt: 'Sender', - dd: , + dd: , }, { dt: 'Approval program', diff --git a/src/features/transaction-wizard/utils/resolve-sender-address.ts b/src/features/transaction-wizard/utils/resolve-sender-address.ts index 260bff28..dcaf238b 100644 --- a/src/features/transaction-wizard/utils/resolve-sender-address.ts +++ b/src/features/transaction-wizard/utils/resolve-sender-address.ts @@ -1,4 +1,3 @@ -import { OptionalSenderFieldSchema } from '@/features/forms/components/address-form-item' import { TESTNET_FEE_SINK_ADDRESS, MAINNET_FEE_SINK_ADDRESS, @@ -11,7 +10,7 @@ import { settingsStore } from '@/features/settings/data' import { betanetId, mainnetId, testnetId, fnetId, localnetId } from '@/features/network/data' import { algorandClient } from '@/features/common/data/algo-client' -export default async function resolveSenderAddress(data: OptionalSenderFieldSchema): Promise { +export default async function resolveSenderAddress(data?: { value?: string; resolvedAddress?: string }): Promise { const { id: networkId } = settingsStore.get(networkConfigAtom) const val = data?.value ?? '' From a0dd3d31b24d7c9f8a50e6717902bbf211aba955 Mon Sep 17 00:00:00 2001 From: Hoang Dinh Date: Fri, 14 Nov 2025 16:55:21 +1000 Subject: [PATCH 14/18] PR feedback --- .../components/transaction-sender-link.tsx | 16 ++-------------- .../forms/components/address-form-item.tsx | 12 +++--------- src/features/forms/components/form.tsx | 2 +- .../components/app-call-transaction-builder.tsx | 2 +- .../application-create-transaction-builder.tsx | 2 +- .../method-call-transaction-builder.tsx | 2 +- .../components/transactions-table.tsx | 1 - src/features/transaction-wizard/data/common.ts | 1 - .../mappers/as-address-or-nfd.ts | 11 ++++------- .../mappers/as-algosdk-transactions.ts | 4 ++-- src/features/transaction-wizard/models/index.ts | 4 +--- .../transaction-wizard-page.tsx | 2 -- .../utils/resolve-sender-address.ts | 2 +- .../transform-search-params-transactions.ts | 2 +- 14 files changed, 18 insertions(+), 45 deletions(-) diff --git a/src/features/accounts/components/transaction-sender-link.tsx b/src/features/accounts/components/transaction-sender-link.tsx index 2769cbbc..9a00b625 100644 --- a/src/features/accounts/components/transaction-sender-link.tsx +++ b/src/features/accounts/components/transaction-sender-link.tsx @@ -1,19 +1,7 @@ -import { Nfd } from '@/features/nfd/data/types' - -import { PropsWithChildren } from 'react' -import { AddressOrNfdLink } from './address-or-nfd-link' -import { Address } from 'algosdk' +import { AddressOrNfdLink, AddressOrNfdLinkProps } from './address-or-nfd-link' import { cn } from '@/features/common/utils' -export type Props = PropsWithChildren<{ - address: string | Address - short?: boolean - className?: string - showCopyButton?: boolean - showQRButton?: boolean - nfd?: Nfd - autoPopulated?: boolean -}> +export type Props = AddressOrNfdLinkProps & { autoPopulated?: boolean } export default function TransactionSenderLink(props: Props) { const { autoPopulated, className, ...rest } = props diff --git a/src/features/forms/components/address-form-item.tsx b/src/features/forms/components/address-form-item.tsx index d0a1fd54..8dc8383b 100644 --- a/src/features/forms/components/address-form-item.tsx +++ b/src/features/forms/components/address-form-item.tsx @@ -11,7 +11,6 @@ import { z } from 'zod' export type AddressOrNfdFieldSchema = z.infer export type OptionalAddressOrNfdFieldSchema = z.infer -export type OptionalSenderFieldSchema = z.infer export interface AddressFieldProps = Record> extends Omit, 'children'> { @@ -42,14 +41,9 @@ function ResolveNfdAddress({ nfd, onNfdResolved }: ResolveNfdAddressProps) { } export function AddressFormItem({ field, resolvedAddressField, label, ...props }: AddressFormItemProps) { - const { watch, setValue } = useFormContext() - const rawValue = watch(field) - - //type guard - const value = typeof rawValue === 'string' ? rawValue : '' - - const rawResolved = watch(resolvedAddressField) - const resolvedAddress = typeof rawResolved === 'string' ? rawResolved : '' + const { watch, setValue } = useFormContext() + const value = watch(field) as string + const resolvedAddress = watch(resolvedAddressField) as string const setAddress = useCallback((address: string) => setValue(resolvedAddressField, address), [resolvedAddressField, setValue]) useEffect(() => { diff --git a/src/features/forms/components/form.tsx b/src/features/forms/components/form.tsx index 25100ee9..952b468b 100644 --- a/src/features/forms/components/form.tsx +++ b/src/features/forms/components/form.tsx @@ -16,7 +16,7 @@ export interface FormProps> { children: | ReactNode | ((helper: FormFieldHelper, handleSubmit: (e?: React.FormEvent) => Promise) => ReactNode) - formAction: ReactNode | ((ctx: UseFormReturn, resetLocalState: () => void) => ReactNode) + formAction: ReactNode | ((ctx: UseFormReturn, resetLocalState: () => void) => ReactNode) onSuccess?: (data: TData) => void onSubmit: (values: z.infer>) => Promise | TData resetOnSuccess?: boolean diff --git a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx index 06215857..0d62b62d 100644 --- a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx @@ -53,7 +53,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de id: transaction?.id ?? randomGuid(), type: BuildableTransactionType.AppCall, applicationId: BigInt(values.applicationId), - sender: await resolveSenderAddress(values.sender!), + sender: await resolveSenderAddress(values.sender), onComplete: Number(values.onComplete), extraProgramPages: values.extraProgramPages, fee: values.fee, diff --git a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx index 250f6431..0347cbde 100644 --- a/src/features/transaction-wizard/components/application-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/application-create-transaction-builder.tsx @@ -58,7 +58,7 @@ export function ApplicationCreateTransactionBuilder({ mode, transaction, activeA type: BuildableTransactionType.ApplicationCreate, approvalProgram: values.approvalProgram, clearStateProgram: values.clearStateProgram, - sender: await resolveSenderAddress(values.sender!), + sender: await resolveSenderAddress(values.sender), onComplete: Number(values.onComplete), extraProgramPages: values.extraProgramPages, globalInts: values.globalInts, diff --git a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx index a2032f90..e59874d0 100644 --- a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx @@ -157,7 +157,7 @@ export function MethodCallTransactionBuilder({ applicationId: BigInt(values.applicationId), methodDefinition: methodDefinition, onComplete: Number(values.onComplete), - sender: await resolveSenderAddress(values.sender!), + sender: await resolveSenderAddress(values.sender), extraProgramPages: values.extraProgramPages, appSpec: appSpec!, methodArgs: methodArgs, diff --git a/src/features/transaction-wizard/components/transactions-table.tsx b/src/features/transaction-wizard/components/transactions-table.tsx index 9c996cfb..2aaa9a78 100644 --- a/src/features/transaction-wizard/components/transactions-table.tsx +++ b/src/features/transaction-wizard/components/transactions-table.tsx @@ -216,7 +216,6 @@ const getTableColumns = ({ return transactionPositions.get(transaction.id)! }, }, - { header: 'Type', accessorFn: (item) => asTransactionLabelFromBuildableTransactionType(item.type), diff --git a/src/features/transaction-wizard/data/common.ts b/src/features/transaction-wizard/data/common.ts index b998d2e8..afd5f739 100644 --- a/src/features/transaction-wizard/data/common.ts +++ b/src/features/transaction-wizard/data/common.ts @@ -49,7 +49,6 @@ export const optionalAddressFieldSchema = z }) export const senderFieldSchema = { sender: addressFieldSchema } - export const receiverFieldSchema = { receiver: addressFieldSchema } export const noteFieldSchema = { note: zfd.text(z.string().optional()) } diff --git a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts index 8b7a765d..01f11b21 100644 --- a/src/features/transaction-wizard/mappers/as-address-or-nfd.ts +++ b/src/features/transaction-wizard/mappers/as-address-or-nfd.ts @@ -16,13 +16,10 @@ export const asAddressOrNfd = (addressOrAccount: Address | ActiveWalletAccount): } satisfies AddressOrNfd } -export const asOptionalAddressOrNfd = (addressOrNfdSchema?: Partial): AddressOrNfd | undefined => { - if (!addressOrNfdSchema) return undefined - if (!addressOrNfdSchema.value || !addressOrNfdSchema.resolvedAddress) return undefined - return { - value: addressOrNfdSchema.value, - resolvedAddress: addressOrNfdSchema.resolvedAddress, - } satisfies AddressOrNfd +export const asOptionalAddressOrNfd = (addressOrNfdSchema: Partial) => { + return addressOrNfdSchema.value && addressOrNfdSchema.resolvedAddress + ? ({ value: addressOrNfdSchema.value, resolvedAddress: addressOrNfdSchema.resolvedAddress } satisfies AddressOrNfd) + : undefined } export const asOptionalAddressOrNfdSchema = (address?: Address) => { diff --git a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts index 22dff33e..aa0d91d6 100644 --- a/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts +++ b/src/features/transaction-wizard/mappers/as-algosdk-transactions.ts @@ -391,10 +391,10 @@ const asKeyRegistrationTransaction = async (transaction: BuildKeyRegistrationTra : algorandClient.createTransaction.offlineKeyRegistration(params)) } -export const asFee = (fee: BuildAssetCreateTransactionResult['fee']) => +const asFee = (fee: BuildAssetCreateTransactionResult['fee']) => !fee.setAutomatically && fee.value != null ? { staticFee: algos(fee.value) } : undefined -export const asValidRounds = (validRounds: BuildAssetCreateTransactionResult['validRounds']) => +const asValidRounds = (validRounds: BuildAssetCreateTransactionResult['validRounds']) => !validRounds.setAutomatically && validRounds.firstValid && validRounds.lastValid ? { firstValidRound: validRounds.firstValid, diff --git a/src/features/transaction-wizard/models/index.ts b/src/features/transaction-wizard/models/index.ts index 8e4185fe..b4eb5adf 100644 --- a/src/features/transaction-wizard/models/index.ts +++ b/src/features/transaction-wizard/models/index.ts @@ -65,9 +65,7 @@ export type AddressOrNfd = { resolvedAddress: Address } -export type TransactionSender = { - value: Address | Nfd - resolvedAddress: Address +export type TransactionSender = AddressOrNfd & { autoPopulated?: boolean } diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 0dbea7be..1a3bddd4 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -19,7 +19,6 @@ export const sendButtonLabel = 'Send' export function TransactionWizardPage() { const [sendResults, setSendResults] = useState(undefined) const searchParamsTransactions = useTransactionSearchParamsBuilder() - useTitle('Transaction Wizard') const renderTransactionResults = useCallback((result: SendTransactionResults, simulateResponse?: algosdk.modelsv2.SimulateResponse) => { @@ -46,7 +45,6 @@ export function TransactionWizardPage() { async (result: SimulateResult) => { renderTransactionResults(result, result.simulateResponse) }, - [renderTransactionResults] ) diff --git a/src/features/transaction-wizard/utils/resolve-sender-address.ts b/src/features/transaction-wizard/utils/resolve-sender-address.ts index dcaf238b..6a2f4490 100644 --- a/src/features/transaction-wizard/utils/resolve-sender-address.ts +++ b/src/features/transaction-wizard/utils/resolve-sender-address.ts @@ -10,7 +10,7 @@ import { settingsStore } from '@/features/settings/data' import { betanetId, mainnetId, testnetId, fnetId, localnetId } from '@/features/network/data' import { algorandClient } from '@/features/common/data/algo-client' -export default async function resolveSenderAddress(data?: { value?: string; resolvedAddress?: string }): Promise { +export default async function resolveSenderAddress(data: { value?: string; resolvedAddress?: string }): Promise { const { id: networkId } = settingsStore.get(networkConfigAtom) const val = data?.value ?? '' diff --git a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts index 7b00face..e4d30efc 100644 --- a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts +++ b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts @@ -362,7 +362,7 @@ export async function transformSearchParamsTransactions(searchParamTransactions: } const { transform, schema } = transformationConfigByTransactionType[configKey as keyof typeof transformationConfigByTransactionType] try { - const transaction = await Promise.resolve(transform(searchParamTransaction)) + const transaction = await transform(searchParamTransaction) schema.parse(transaction) transactionsFromSearchParams.push(transaction) } catch (error) { From a9d770b7fafd2b999e46e70b8bf2b3996026aa9c Mon Sep 17 00:00:00 2001 From: p2arthur Date: Sun, 16 Nov 2025 14:02:39 -0800 Subject: [PATCH 15/18] test(optional_sender): updated tests to use kmd instead of assuming testWallet + address PR comments --- package-lock.json | 158 +++++++++--------- .../components/transaction-sender-link.tsx | 16 +- .../asset-create-transaction-builder.tsx | 10 +- .../asset-reconfigure-transaction-builder.tsx | 10 +- .../components/transactions-builder.tsx | 6 +- .../transaction-wizard-page.test.tsx | 51 +++--- .../transaction-wizard-page.tsx | 22 ++- .../utils/resolve-sender-address.ts | 3 +- .../use-transaction-search-params-builder.ts | 22 +-- .../utils/set-wallet-address-and-signer.ts | 10 +- 10 files changed, 153 insertions(+), 155 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2894988c..956305d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4282,9 +4282,9 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", - "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", + "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", "dev": true, "license": "MIT", "dependencies": { @@ -4292,39 +4292,39 @@ "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", - "magic-string": "^0.30.21", + "magic-string": "^0.30.19", "source-map-js": "^1.2.1", - "tailwindcss": "4.1.17" + "tailwindcss": "4.1.16" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", - "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", + "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", "dev": true, "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-x64": "4.1.17", - "@tailwindcss/oxide-freebsd-x64": "4.1.17", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-x64-musl": "4.1.17", - "@tailwindcss/oxide-wasm32-wasi": "4.1.17", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" + "@tailwindcss/oxide-android-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-arm64": "4.1.16", + "@tailwindcss/oxide-darwin-x64": "4.1.16", + "@tailwindcss/oxide-freebsd-x64": "4.1.16", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", + "@tailwindcss/oxide-linux-x64-musl": "4.1.16", + "@tailwindcss/oxide-wasm32-wasi": "4.1.16", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", - "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", + "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", "cpu": [ "arm64" ], @@ -4339,9 +4339,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", - "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", + "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", "cpu": [ "arm64" ], @@ -4356,9 +4356,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", - "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", + "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", "cpu": [ "x64" ], @@ -4373,9 +4373,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", - "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", + "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", "cpu": [ "x64" ], @@ -4390,9 +4390,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", - "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", + "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", "cpu": [ "arm" ], @@ -4407,9 +4407,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", - "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", + "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", "cpu": [ "arm64" ], @@ -4424,9 +4424,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", - "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", + "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", "cpu": [ "arm64" ], @@ -4441,9 +4441,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", - "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", + "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", "cpu": [ "x64" ], @@ -4458,9 +4458,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", - "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", + "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", "cpu": [ "x64" ], @@ -4475,9 +4475,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", - "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", + "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -4493,8 +4493,8 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.6.0", - "@emnapi/runtime": "^1.6.0", + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", @@ -4505,9 +4505,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", - "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", + "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", "cpu": [ "arm64" ], @@ -4522,9 +4522,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", - "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", + "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", "cpu": [ "x64" ], @@ -4539,29 +4539,29 @@ } }, "node_modules/@tailwindcss/postcss": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz", - "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.16.tgz", + "integrity": "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==", "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.17", - "@tailwindcss/oxide": "4.1.17", + "@tailwindcss/node": "4.1.16", + "@tailwindcss/oxide": "4.1.16", "postcss": "^8.4.41", - "tailwindcss": "4.1.17" + "tailwindcss": "4.1.16" } }, "node_modules/@tailwindcss/vite": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.17.tgz", - "integrity": "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz", + "integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==", "dev": true, "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.1.17", - "@tailwindcss/oxide": "4.1.17", - "tailwindcss": "4.1.17" + "@tailwindcss/node": "4.1.16", + "@tailwindcss/oxide": "4.1.16", + "tailwindcss": "4.1.16" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" @@ -9670,9 +9670,9 @@ } }, "node_modules/html2canvas-pro": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/html2canvas-pro/-/html2canvas-pro-1.5.13.tgz", - "integrity": "sha512-//ksb3JLA+ewSxFODyb5YH6xqRLpe6Kt1i7Zyr5eqHmfcNt0bm8MpzSQjOK2qu6cCv13wqWtOZrCOpA+//EhaA==", + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/html2canvas-pro/-/html2canvas-pro-1.5.12.tgz", + "integrity": "sha512-egtJIe6YXMKSLX/ls400OJD6tzEVtATJOE++mnXmxMWyqcu9HDXDoLiWeXnGv45QW2ZaIiDlXw46Gxqrqw6SEw==", "license": "MIT", "dependencies": { "css-line-break": "^2.1.0", @@ -18043,9 +18043,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", - "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", + "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", "dev": true, "license": "MIT" }, @@ -18945,9 +18945,9 @@ } }, "node_modules/vite": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", - "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.0.tgz", + "integrity": "sha512-C/Naxf8H0pBx1PA4BdpT+c/5wdqI9ILMdwjSMILw7tVIh3JsxzZqdeTLmmdaoh5MYUEOyBnM9K3o0DzoZ/fe+w==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/features/accounts/components/transaction-sender-link.tsx b/src/features/accounts/components/transaction-sender-link.tsx index 2769cbbc..881df1e2 100644 --- a/src/features/accounts/components/transaction-sender-link.tsx +++ b/src/features/accounts/components/transaction-sender-link.tsx @@ -1,19 +1,9 @@ -import { Nfd } from '@/features/nfd/data/types' - -import { PropsWithChildren } from 'react' -import { AddressOrNfdLink } from './address-or-nfd-link' -import { Address } from 'algosdk' +import { AddressOrNfdLink, AddressOrNfdLinkProps } from './address-or-nfd-link' import { cn } from '@/features/common/utils' -export type Props = PropsWithChildren<{ - address: string | Address - short?: boolean - className?: string - showCopyButton?: boolean - showQRButton?: boolean - nfd?: Nfd +export type Props = AddressOrNfdLinkProps & { autoPopulated?: boolean -}> +} export default function TransactionSenderLink(props: Props) { const { autoPopulated, className, ...rest } = props diff --git a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx index de41f6ac..fb719bb0 100644 --- a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx @@ -15,7 +15,7 @@ import { FormFieldHelper } from '@/features/forms/components/form-field-helper' import { ZERO_ADDRESS } from '@/features/common/constants' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asOptionalAddressOrNfd } from '../mappers/as-address-or-nfd' import { ActiveWalletAccount } from '@/features/wallet/types/active-wallet' import resolveSenderAddress from '../utils/resolve-sender-address' @@ -135,10 +135,10 @@ export function AssetCreateTransactionBuilder({ mode, transaction, activeAccount total: data.total, decimals: data.decimals, sender: await resolveSenderAddress(data.sender), - manager: asAddressOrNfd(data.manager.value!), - reserve: asAddressOrNfd(data.reserve.value!), - freeze: asAddressOrNfd(data.freeze.value!), - clawback: asAddressOrNfd(data.clawback.value!), + manager: asOptionalAddressOrNfd(data.manager), + reserve: asOptionalAddressOrNfd(data.reserve), + freeze: asOptionalAddressOrNfd(data.freeze), + clawback: asOptionalAddressOrNfd(data.clawback), defaultFrozen: data.defaultFrozen ?? false, url: data.url, metadataHash: data.metadataHash, diff --git a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx index 9939ba39..06c45bfe 100644 --- a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx @@ -21,7 +21,7 @@ import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' -import { asAddressOrNfd, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' +import { asAddressOrNfd, asOptionalAddressOrNfd, asOptionalAddressOrNfdSchema } from '../mappers/as-address-or-nfd' import resolveSenderAddress from '../utils/resolve-sender-address' export const assetReconfigureFormSchema = z @@ -218,10 +218,10 @@ export function AssetReconfigureTransactionBuilder({ mode, transaction, onSubmit asset: data.asset, sender: await resolveSenderAddress(data.sender), - manager: asAddressOrNfd(data.manager.value!), - reserve: asAddressOrNfd(data.reserve.value!), - freeze: asAddressOrNfd(data.freeze.value!), - clawback: asAddressOrNfd(data.clawback.value!), + manager: asOptionalAddressOrNfd(data.manager), + reserve: asOptionalAddressOrNfd(data.reserve), + freeze: asOptionalAddressOrNfd(data.freeze), + clawback: asOptionalAddressOrNfd(data.clawback), fee: data.fee, validRounds: data.validRounds, note: data.note, diff --git a/src/features/transaction-wizard/components/transactions-builder.tsx b/src/features/transaction-wizard/components/transactions-builder.tsx index 955b721a..95676e45 100644 --- a/src/features/transaction-wizard/components/transactions-builder.tsx +++ b/src/features/transaction-wizard/components/transactions-builder.tsx @@ -1,5 +1,5 @@ import algosdk from 'algosdk' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { DialogBodyProps, useDialogForm } from '@/features/common/hooks/use-dialog-form' import { AsyncActionButton, Button } from '@/features/common/components/button' import { TransactionBuilder } from './transaction-builder' @@ -348,6 +348,10 @@ export function TransactionsBuilder({ return commonButtonDisableProps }, [transactions, activeAddress, commonButtonDisableProps]) + useEffect(() => { + setTransactions(defaultTransactions ?? []) + }, [defaultTransactions]) + return (
diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index 7de7b411..f3a6760c 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -10,6 +10,7 @@ import { setWalletAddressAndSigner } from '@/tests/utils/set-wallet-address-and- import { addTransactionLabel } from './components/transactions-builder' import { groupSendResultsLabel } from './components/group-send-results' import { base64ToBytes } from '@/utils/base64-to-bytes' +import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account' describe('transaction-wizard-page', () => { const localnet = algorandFixture() @@ -46,8 +47,10 @@ describe('transaction-wizard-page', () => { }) describe('when a wallet is connected', () => { + let walletAccount: TransactionSignerAccount + beforeEach(async () => { - await setWalletAddressAndSigner(localnet) + walletAccount = await setWalletAddressAndSigner(localnet) }) describe('and a payment transaction is being sent', () => { @@ -81,7 +84,6 @@ describe('transaction-wizard-page', () => { }) it('succeeds when all fields have been correctly supplied', async () => { - const { testAccount } = localnet.context const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) await executeComponentTest( @@ -98,7 +100,7 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const receiverInput = await component.findByLabelText(/Receiver/) @@ -144,7 +146,7 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` TransactionPayment { "amount": 500000n, @@ -158,7 +160,6 @@ describe('transaction-wizard-page', () => { }) it('Can add a payment transaction without defining a sender address and the sender gets auto populated', async () => { - const { testAccount } = localnet.context const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) await executeComponentTest( @@ -191,7 +192,7 @@ describe('transaction-wizard-page', () => { await user.click(addButton) const senderContent = await waitFor(() => { - return component.getByText(testAccount.addr.toString()) + return component.getByText(walletAccount.addr.toString()) }) expect(senderContent).toBeInTheDocument() @@ -221,7 +222,7 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` TransactionPayment { "amount": 500000n, @@ -267,7 +268,6 @@ describe('transaction-wizard-page', () => { }) it('succeeds when all fields have been correctly supplied', async () => { - const { testAccount } = localnet.context const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) await executeComponentTest( @@ -286,12 +286,12 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const receiverInput = await component.findByLabelText(/Receiver/) fireEvent.input(receiverInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const closeToInput = await component.findByLabelText(/Close remainder to/) @@ -335,13 +335,13 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) expect(result.transaction.paymentTransaction!).toMatchInlineSnapshot(` TransactionPayment { "amount": 0n, "closeAmount": 9999000n, "closeRemainderTo": "${testAccount2.addr}", - "receiver": "${testAccount.addr}", + "receiver": "${walletAccount.addr}", } `) } @@ -349,7 +349,6 @@ describe('transaction-wizard-page', () => { }) it('can simulate a close account transaction without defining a sender address', async () => { - const { testAccount } = localnet.context const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) await executeComponentTest( @@ -368,7 +367,7 @@ describe('transaction-wizard-page', () => { const receiverInput = await component.findByLabelText(/Receiver/) fireEvent.input(receiverInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const closeToInput = await component.findByLabelText(/Close remainder to/) @@ -412,7 +411,6 @@ describe('transaction-wizard-page', () => { describe('and an application create transaction is being sent', () => { it('succeeds when all fields have been correctly supplied', async () => { - const { testAccount } = localnet.context await executeComponentTest( () => { @@ -430,7 +428,7 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const approvalProgram = @@ -481,7 +479,7 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) expect(result.transaction.applicationTransaction!.approvalProgram).toEqual(base64ToBytes(approvalProgram)) expect(result.transaction.applicationTransaction!.clearStateProgram).toEqual(base64ToBytes(clearStateProgram)) } @@ -489,8 +487,6 @@ describe('transaction-wizard-page', () => { }) it('succeeds when sending an op-up transaction', async () => { - const { testAccount } = localnet.context - await executeComponentTest( () => { return render() @@ -507,7 +503,7 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const approvalProgramInput = await component.findByLabelText(/Approval program/) @@ -555,14 +551,12 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) } ) }) it('succeeds when sending an op-up transaction', async () => { - const { testAccount } = localnet.context - await executeComponentTest( () => { return render() @@ -579,7 +573,7 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const approvalProgramInput = await component.findByLabelText(/Approval program/) @@ -627,7 +621,7 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) } ) }) @@ -635,11 +629,10 @@ describe('transaction-wizard-page', () => { describe('and an application update transaction is being sent', () => { it('succeeds when updating an updatable application', async () => { - const { testAccount } = localnet.context // First create an updatable application const appCreateResult = await localnet.context.algorand.send.appCreate({ - sender: testAccount.addr, + sender: walletAccount.addr, approvalProgram: '#pragma version 10\nint 1\nreturn', clearStateProgram: '#pragma version 10\nint 1\nreturn', }) @@ -661,7 +654,7 @@ describe('transaction-wizard-page', () => { const senderInput = await component.findByLabelText(/Sender/) fireEvent.input(senderInput, { - target: { value: testAccount.addr }, + target: { value: walletAccount.addr }, }) const applicationIdInput = await component.findByLabelText(/Application ID/) @@ -713,7 +706,7 @@ describe('transaction-wizard-page', () => { ) const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(testAccount.addr.toString()) + expect(result.transaction.sender).toBe(walletAccount.addr.toString()) expect(result.transaction.applicationTransaction?.onCompletion).toBe('update') expect(result.transaction.applicationTransaction!.approvalProgram).toEqual(base64ToBytes(program)) expect(result.transaction.applicationTransaction!.clearStateProgram).toEqual(base64ToBytes(program)) diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 0dbea7be..b9fd6fde 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -11,6 +11,7 @@ import { GroupSendResults, SendResults } from './components/group-send-results' import algosdk from 'algosdk' import { useTitle } from '@/utils/use-title' import { useTransactionSearchParamsBuilder } from './utils/use-transaction-search-params-builder' +import { PageLoader } from '../common/components/page-loader' export const transactionWizardPageTitle = 'Transaction Wizard' export const transactionTypeLabel = 'Transaction type' @@ -18,7 +19,7 @@ export const sendButtonLabel = 'Send' export function TransactionWizardPage() { const [sendResults, setSendResults] = useState(undefined) - const searchParamsTransactions = useTransactionSearchParamsBuilder() + const { transactions: searchParamsTransactions, loading: transactionsLoading } = useTransactionSearchParamsBuilder() useTitle('Transaction Wizard') @@ -59,14 +60,17 @@ export function TransactionWizardPage() {

Create and send transactions to the selected network using a connected wallet.

- t.id).join('|')} // rerender when it gets populated - defaultTransactions={searchParamsTransactions.transactions} - title={

{transactionGroupLabel}

} - onSendTransactions={sendTransactions} - onSimulated={renderSimulateResult} - onReset={reset} - /> + {transactionsLoading ? ( + + ) : ( + {transactionGroupLabel}} + onSendTransactions={sendTransactions} + onSimulated={renderSimulateResult} + onReset={reset} + /> + )} {sendResults && }
diff --git a/src/features/transaction-wizard/utils/resolve-sender-address.ts b/src/features/transaction-wizard/utils/resolve-sender-address.ts index dcaf238b..1849f255 100644 --- a/src/features/transaction-wizard/utils/resolve-sender-address.ts +++ b/src/features/transaction-wizard/utils/resolve-sender-address.ts @@ -35,11 +35,12 @@ export default async function resolveSenderAddress(data?: { value?: string; reso if (networkId === testnetId) { return { value: TESTNET_FEE_SINK_ADDRESS, resolvedAddress: TESTNET_FEE_SINK_ADDRESS, autoPopulated: true } } + + throw new Error('Unable to auto-populate a sender for the selected network; please provide a sender address.') } return { value: val || res, resolvedAddress: res || val, - autoPopulated: false, } } diff --git a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts index 5df61b21..dd884d2d 100644 --- a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts +++ b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts @@ -31,27 +31,29 @@ export function useTransactionSearchParamsBuilder() { ) const [transactions, setTransactions] = useState([]) - const [errors, setErrors] = useState([]) const [loading, setLoading] = useState(false) useEffect(() => { - let cancelled = false - ;(async () => { + let mounted = true + const loadTransactions = async () => { setLoading(true) try { const { transactions, errors = [] } = await transformSearchParamsTransactions(transformedParams) + if (!mounted) return setTransactions(transactions) - setErrors(errors) - // show toasts once per change - if (errors.length) errors.forEach((e) => toast.error(e)) + errors.forEach((error) => toast.error(error)) } finally { - if (!cancelled) setLoading(false) + if (mounted) { + setLoading(false) + } } - })() + } + + loadTransactions() return () => { - cancelled = true + mounted = false } }, [transformedParams]) - return { transactions, errors, loading } + return { transactions, loading } } diff --git a/src/tests/utils/set-wallet-address-and-signer.ts b/src/tests/utils/set-wallet-address-and-signer.ts index a018416d..3afd1bf0 100644 --- a/src/tests/utils/set-wallet-address-and-signer.ts +++ b/src/tests/utils/set-wallet-address-and-signer.ts @@ -1,17 +1,21 @@ import { AlgorandFixture } from '@algorandfoundation/algokit-utils/types/testing' import { vi } from 'vitest' import { useWallet } from '@txnlab/use-wallet-react' +import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account' -export const setWalletAddressAndSigner = async (localnet: AlgorandFixture) => { +export const setWalletAddressAndSigner = async (localnet: AlgorandFixture): Promise => { const { testAccount } = localnet.context + const walletAccount = localnet.algorand.account.getAccount(testAccount.addr.toString()) const original = await vi.importActual<{ useWallet: () => ReturnType }>('@txnlab/use-wallet-react') vi.mocked(useWallet).mockImplementation(() => { return { ...original.useWallet(), - activeAddress: testAccount.addr.toString(), - transactionSigner: testAccount.signer, + activeAddress: walletAccount.addr.toString(), + transactionSigner: walletAccount.signer, isReady: true, } satisfies ReturnType }) + + return walletAccount } From 59aca015aedaea3bd77ac352538050d63f706533 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Sun, 16 Nov 2025 14:12:22 -0800 Subject: [PATCH 16/18] fix(audit): fix audit warning blocking ci --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 956305d3..1467e124 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10592,9 +10592,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { From 235900aecf6413cf2509217c8ee60c111d401c35 Mon Sep 17 00:00:00 2001 From: p2arthur Date: Sun, 16 Nov 2025 14:41:46 -0800 Subject: [PATCH 17/18] chore(optional_sender): cleanup to remove repeated tests and optional fields that got required --- .../transaction-wizard-page.test.tsx | 138 ------------------ .../transform-search-params-transactions.ts | 2 + .../use-transaction-search-params-builder.ts | 19 +-- 3 files changed, 8 insertions(+), 151 deletions(-) diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index f3a6760c..e3bc9101 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -289,19 +289,11 @@ describe('transaction-wizard-page', () => { target: { value: walletAccount.addr }, }) - const receiverInput = await component.findByLabelText(/Receiver/) - fireEvent.input(receiverInput, { - target: { value: walletAccount.addr }, - }) - const closeToInput = await component.findByLabelText(/Close remainder to/) fireEvent.input(closeToInput, { target: { value: testAccount2.addr }, }) - const amountInput = await component.findByLabelText(/Amount to pay/) - fireEvent.input(amountInput, { target: { value: '0' } }) - const addButton = await waitFor(() => { const addButton = component.getByRole('button', { name: 'Add' }) expect(addButton).not.toBeDisabled() @@ -347,66 +339,6 @@ describe('transaction-wizard-page', () => { } ) }) - - it('can simulate a close account transaction without defining a sender address', async () => { - const testAccount2 = await localnet.context.generateAccount({ initialFunds: algo(0) }) - - await executeComponentTest( - () => { - return render() - }, - async (component, user) => { - const addTransactionButton = await waitFor(() => { - const addTransactionButton = component.getByRole('button', { name: addTransactionLabel }) - expect(addTransactionButton).not.toBeDisabled() - return addTransactionButton! - }) - await user.click(addTransactionButton) - - await selectOption(component.baseElement, user, transactionTypeLabel, 'Account Close (pay)') - - const receiverInput = await component.findByLabelText(/Receiver/) - fireEvent.input(receiverInput, { - target: { value: walletAccount.addr }, - }) - - const closeToInput = await component.findByLabelText(/Close remainder to/) - fireEvent.input(closeToInput, { - target: { value: testAccount2.addr }, - }) - - const amountInput = await component.findByLabelText(/Amount to pay/) - fireEvent.input(amountInput, { target: { value: '0' } }) - - const addButton = await waitFor(() => { - const addButton = component.getByRole('button', { name: 'Add' }) - expect(addButton).not.toBeDisabled() - return addButton! - }) - await user.click(addButton) - - await waitFor(() => { - const table = component.getByLabelText('transaction-group-table') - expect(table).toBeInTheDocument() - expect(component.queryByText('No transactions.')).not.toBeInTheDocument() - }) - - const simulateButton = await waitFor(() => { - const simulateButton = component.getByRole('button', { name: 'Simulate' }) - expect(simulateButton).not.toBeDisabled() - return simulateButton! - }) - - await user.click(simulateButton) - await waitFor( - () => { - expect(component.queryByText(/error/i)).not.toBeInTheDocument() - }, - { timeout: 5_000 } - ) - } - ) - }) }) describe('and an application create transaction is being sent', () => { @@ -555,76 +487,6 @@ describe('transaction-wizard-page', () => { } ) }) - - it('succeeds when sending an op-up transaction', async () => { - await executeComponentTest( - () => { - return render() - }, - async (component, user) => { - const addTransactionButton = await waitFor(() => { - const addTransactionButton = component.getByRole('button', { name: addTransactionLabel }) - expect(addTransactionButton).not.toBeDisabled() - return addTransactionButton! - }) - await user.click(addTransactionButton) - - await selectOption(component.baseElement, user, transactionTypeLabel, 'Application Create (appl)') - - const senderInput = await component.findByLabelText(/Sender/) - fireEvent.input(senderInput, { - target: { value: walletAccount.addr }, - }) - - const approvalProgramInput = await component.findByLabelText(/Approval program/) - fireEvent.input(approvalProgramInput, { - target: { value: 'CoEBQw==' }, - }) - - const clearStateProgramInput = await component.findByLabelText(/Clear state program/) - fireEvent.input(clearStateProgramInput, { - target: { value: 'CoEBQw==' }, - }) - - await selectOption(component.baseElement, user, /On complete/, 'Delete') - - const addButton = await waitFor(() => { - const addButton = component.getByRole('button', { name: 'Add' }) - expect(addButton).not.toBeDisabled() - return addButton! - }) - await user.click(addButton) - - const sendButton = await waitFor(() => { - const sendButton = component.getByRole('button', { name: sendButtonLabel }) - expect(sendButton).not.toBeDisabled() - return sendButton! - }) - await user.click(sendButton) - - const resultsDiv = await waitFor( - () => { - expect(component.queryByText('Required')).not.toBeInTheDocument() - return component.getByText(groupSendResultsLabel).parentElement! - }, - { timeout: 10_000 } - ) - - const transactionId = await waitFor( - () => { - const transactionLink = within(resultsDiv) - .getAllByRole('link') - .find((a) => a.getAttribute('href')?.startsWith('/localnet/transaction'))! - return transactionLink.getAttribute('href')!.split('/').pop()! - }, - { timeout: 10_000 } - ) - - const result = await localnet.context.waitForIndexerTransaction(transactionId) - expect(result.transaction.sender).toBe(walletAccount.addr.toString()) - } - ) - }) }) describe('and an application update transaction is being sent', () => { diff --git a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts index 7b00face..ff8fb89e 100644 --- a/src/features/transaction-wizard/utils/transform-search-params-transactions.ts +++ b/src/features/transaction-wizard/utils/transform-search-params-transactions.ts @@ -132,6 +132,7 @@ const transformAssetOptInTransaction = async (params: BaseSearchParamTransaction id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, unitName: params.unitname, + clawback: params.clawback, }, fee: params.fee ? { setAutomatically: false, value: microAlgo(Number(params.fee)).algo } : { setAutomatically: true }, validRounds: { @@ -151,6 +152,7 @@ const transformAssetOptOutTransaction = async (params: BaseSearchParamTransactio id: BigInt(params.assetid), decimals: params.decimals ? Number(params.decimals) : undefined, unitName: params.unitname, + clawback: params.clawback, }, closeRemainderTo: { value: params.closeto, diff --git a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts index dd884d2d..5f163d85 100644 --- a/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts +++ b/src/features/transaction-wizard/utils/use-transaction-search-params-builder.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useState } from 'react' import { useSearchParams } from 'react-router-dom' import { toast } from 'react-toastify' import { transformSearchParamsTransactions } from './transform-search-params-transactions' @@ -7,29 +7,21 @@ import type { BaseSearchParamTransaction, BuildTransactionResult } from '../mode const transformSearchParams = (searchParams: URLSearchParams) => { const entries = Array.from(searchParams.entries()) - const grouped = entries.reduce((acc, [key, value]) => { + const groupedParams = entries.reduce((acc, [key, value]) => { const match = key.match(/^([^[]+)\[(\d+)\]$/) if (!match) return acc const [, paramName, index] = match const idx = parseInt(index, 10) - acc[idx] ??= { type: '' } // ensure slot exists; keep your original default + acc[idx] ??= { type: '' } acc[idx][paramName] = value return acc }, []) - return grouped.filter((entry) => Object.keys(entry).length > 0) + return groupedParams.filter((entry) => Object.keys(entry).length > 0) } export function useTransactionSearchParamsBuilder() { const [searchParams] = useSearchParams() - - // memoize the parsed params so effect only runs when params actually change - const transformedParams = useMemo( - () => transformSearchParams(searchParams), - // URLSearchParams is mutable; tie memoization to its string form - [searchParams] - ) - const [transactions, setTransactions] = useState([]) const [loading, setLoading] = useState(false) @@ -38,6 +30,7 @@ export function useTransactionSearchParamsBuilder() { const loadTransactions = async () => { setLoading(true) try { + const transformedParams = transformSearchParams(searchParams) const { transactions, errors = [] } = await transformSearchParamsTransactions(transformedParams) if (!mounted) return setTransactions(transactions) @@ -53,7 +46,7 @@ export function useTransactionSearchParamsBuilder() { return () => { mounted = false } - }, [transformedParams]) + }, [searchParams]) return { transactions, loading } } From b26d3a5ff17bfc56b844db0eb64eb0b72ba6eea2 Mon Sep 17 00:00:00 2001 From: p2arthur <84791111+p2arthur@users.noreply.github.com> Date: Tue, 18 Nov 2025 07:08:18 -0800 Subject: [PATCH 18/18] Destructure loading from useTransactionSearchParamsBuilder --- src/features/transaction-wizard/transaction-wizard-page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 9d22906d..18e6f1d5 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -19,9 +19,9 @@ export const sendButtonLabel = 'Send' export function TransactionWizardPage() { const [sendResults, setSendResults] = useState(undefined) - const searchParamsTransactions = useTransactionSearchParamsBuilder() + const { transactions: searchParamsTransactions, loading: transactionsLoading } = useTransactionSearchParamsBuilder() useTitle('Transaction Wizard') - + const renderTransactionResults = useCallback((result: SendTransactionResults, simulateResponse?: algosdk.modelsv2.SimulateResponse) => { const sentTransactions = asTransactionFromSendResult(result) const transactionsGraphData = asTransactionsGraphData(sentTransactions)