diff --git a/package-lock.json b/package-lock.json index 81f8a8a919e..6b4fc990512 100644 --- a/package-lock.json +++ b/package-lock.json @@ -165,12 +165,6 @@ "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/provider-utils/node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, "node_modules/@ai-sdk/provider/node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -1383,6 +1377,10 @@ "slide": "^1.1.5" } }, + "node_modules/@audius/migrate-tool": { + "resolved": "packages/migrate-tool", + "link": true + }, "node_modules/@audius/mobile": { "resolved": "packages/mobile", "link": true @@ -7115,6 +7113,59 @@ "@noble/ciphers": "^1.0.0" } }, + "node_modules/@edge-runtime/format": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-2.2.1.tgz", + "integrity": "sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/node-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/node-utils/-/node-utils-2.3.0.tgz", + "integrity": "sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/ponyfill": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/ponyfill/-/ponyfill-2.4.2.tgz", + "integrity": "sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/primitives": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.1.0.tgz", + "integrity": "sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/vm": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-3.2.0.tgz", + "integrity": "sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@edge-runtime/primitives": "4.1.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@egjs/hammerjs": { "version": "2.0.17", "license": "MIT", @@ -8340,6 +8391,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/linux-mips64el": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", @@ -8754,7 +8821,9 @@ } }, "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", "funding": [ { "type": "individual", @@ -8767,13 +8836,21 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "bn.js": "^5.2.1" } }, + "node_modules/@ethersproject/bignumber/node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "license": "MIT" + }, "node_modules/@ethersproject/bytes": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", "funding": [ { "type": "individual", @@ -8786,11 +8863,13 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/constants": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", "funding": [ { "type": "individual", @@ -8803,7 +8882,7 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0" } }, "node_modules/@ethersproject/contracts": { @@ -8918,7 +8997,9 @@ "license": "MIT" }, "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", "funding": [ { "type": "individual", @@ -8931,12 +9012,14 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", "js-sha3": "0.8.0" } }, "node_modules/@ethersproject/logger": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", "funding": [ { "type": "individual", @@ -9096,7 +9179,9 @@ } }, "node_modules/@ethersproject/sha2": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", "funding": [ { "type": "individual", @@ -9109,8 +9194,8 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "hash.js": "1.1.7" } }, @@ -9148,7 +9233,9 @@ } }, "node_modules/@ethersproject/strings": { - "version": "5.7.0", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", "funding": [ { "type": "individual", @@ -9161,9 +9248,9 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/transactions": { @@ -15288,6 +15375,128 @@ "version": "4.1.0", "license": "MIT" }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/@marijn/find-cluster-break": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", @@ -17660,20 +17869,6 @@ "node": ">=10" } }, - "node_modules/@npmcli/move-file/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@npmcli/name-from-folder": { "version": "2.0.0", "dev": true, @@ -30252,22 +30447,6 @@ "node": ">=10" } }, - "node_modules/@rnx-kit/chromium-edge-launcher/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.47", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", @@ -34740,6 +34919,12 @@ ], "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, "node_modules/@stripe/crypto": { "version": "0.0.4", "license": "MIT", @@ -34755,6 +34940,116 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/@supabase/auth-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.99.2.tgz", + "integrity": "sha512-uRGNXMKEw4VhwouNW7N0XDAGqJP9redHNDmWi17dTrcO1lvFfyRiXsqqfgnVC8aqtRn8kLkLPEzHjiRWsni+oQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.99.2.tgz", + "integrity": "sha512-xuXQARvjdfB1UPK1yUceZ5EGjOLkVz4rBAaloS9foXiAuseWEdgWBCxkIAFRxGBLGX8Uzo8kseq90jhPb+07Vg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.99.2.tgz", + "integrity": "sha512-ueiOVkbkTQ7RskwVmjR8zxWYw3VKOMxo1+qep+Dx/SgApqyhWBGd92waQb45tbLc7ydB5x8El8utXOLQTuTojQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.99.2.tgz", + "integrity": "sha512-J6Jm9601dkpZf3+EJ48ki2pM4sFtCNm/BI0l8iEnrczgg+JSEQkMoOW5VSpM54t0pNs69bsz5PTmYJahDZKiIQ==", + "license": "MIT", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@supabase/realtime-js/node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.99.2.tgz", + "integrity": "sha512-V/FF8kX8JGSefsVCG1spCLSrHdNR/JFeUMn1jS9KG/Eizjx+evtdKQKLJXFgIylY/bKTXKhc2SYDPIGrIhzsug==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.99.2", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.99.2.tgz", + "integrity": "sha512-179rn5wq0wBAqqGwAwR7TUGg2NOaP+fkd5FCVbYJXby85fsRNPFoNJN8YRBepqX2tN7JJcnTjqaAMXuNjiyisA==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.99.2", + "@supabase/functions-js": "2.99.2", + "@supabase/postgrest-js": "2.99.2", + "@supabase/realtime-js": "2.99.2", + "@supabase/storage-js": "2.99.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "license": "MIT", @@ -37726,6 +38021,32 @@ "node": ">=10.13.0" } }, + "node_modules/@ts-morph/common": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", + "integrity": "sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.7", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "license": "MIT" @@ -38600,6 +38921,12 @@ "pg-types": "^2.2.0" } }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", + "license": "MIT" + }, "node_modules/@types/pify": { "version": "5.0.1", "dev": true, @@ -38696,6 +39023,16 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-helmet": { "version": "6.1.6", "dev": true, @@ -40912,6 +41249,220 @@ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/@vercel/build-utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-8.7.0.tgz", + "integrity": "sha512-ofZX+ABiW76u5khIyYyH5xK5KSuiAteqRu5hz2k1a2WHLwF7VpeBg8gdFR+HwbVnNkHtkMA64ya5Dd/lNoABkw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/error-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@vercel/error-utils/-/error-utils-2.0.3.tgz", + "integrity": "sha512-CqC01WZxbLUxoiVdh9B/poPbNpY9U+tO1N9oWHwTl5YAZxcqXmmWJ8KNMFItJCUUWdY3J3xv8LvAuQv2KZ5YdQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/nft": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.27.3.tgz", + "integrity": "sha512-oySTdDSzUAFDXpsSLk9Q943o+/Yu/+TCFxnehpFQEf/3khi2stMpTHPVNwFdvZq/Z4Ky93lE+MGHpXCRpMkSCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.5", + "@rollup/pluginutils": "^4.0.0", + "acorn": "^8.6.0", + "acorn-import-attributes": "^1.9.5", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.2", + "node-gyp-build": "^4.2.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "nft": "out/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vercel/nft/node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@vercel/nft/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@vercel/node": { + "version": "3.2.29", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-3.2.29.tgz", + "integrity": "sha512-WRVYidBqtRyYUw36v/WyUB2v97PsiV2+LepUiOPWcW9UpszQGGT2DAzsXOYqWveXMJKFhx0aETR6Nn6i+Yps1Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@edge-runtime/node-utils": "2.3.0", + "@edge-runtime/primitives": "4.1.0", + "@edge-runtime/vm": "3.2.0", + "@types/node": "16.18.11", + "@vercel/build-utils": "8.7.0", + "@vercel/error-utils": "2.0.3", + "@vercel/nft": "0.27.3", + "@vercel/static-config": "3.0.0", + "async-listen": "3.0.0", + "cjs-module-lexer": "1.2.3", + "edge-runtime": "2.5.9", + "es-module-lexer": "1.4.1", + "esbuild": "0.14.47", + "etag": "1.8.1", + "node-fetch": "2.6.9", + "path-to-regexp": "6.2.1", + "ts-morph": "12.0.0", + "ts-node": "10.9.1", + "typescript": "4.9.5", + "undici": "5.28.4" + } + }, + "node_modules/@vercel/node/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/node/node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/node/node_modules/esbuild": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", + "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.47", + "esbuild-android-arm64": "0.14.47", + "esbuild-darwin-64": "0.14.47", + "esbuild-darwin-arm64": "0.14.47", + "esbuild-freebsd-64": "0.14.47", + "esbuild-freebsd-arm64": "0.14.47", + "esbuild-linux-32": "0.14.47", + "esbuild-linux-64": "0.14.47", + "esbuild-linux-arm": "0.14.47", + "esbuild-linux-arm64": "0.14.47", + "esbuild-linux-mips64le": "0.14.47", + "esbuild-linux-ppc64le": "0.14.47", + "esbuild-linux-riscv64": "0.14.47", + "esbuild-linux-s390x": "0.14.47", + "esbuild-netbsd-64": "0.14.47", + "esbuild-openbsd-64": "0.14.47", + "esbuild-sunos-64": "0.14.47", + "esbuild-windows-32": "0.14.47", + "esbuild-windows-64": "0.14.47", + "esbuild-windows-arm64": "0.14.47" + } + }, + "node_modules/@vercel/node/node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@vercel/node/node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/node/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/node/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@vercel/node/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@vercel/node/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/@vercel/oidc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", @@ -40921,6 +41472,253 @@ "node": ">= 20" } }, + "node_modules/@vercel/static-config": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-3.0.0.tgz", + "integrity": "sha512-2qtvcBJ1bGY0dYGYh3iM7yGKkk971FujLEDXzuW5wcZsPr1GSEjO/w2iSr3qve6nDDtBImsGoDEnus5FI4+fIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ajv": "8.6.3", + "json-schema-to-ts": "1.6.4", + "ts-morph": "12.0.0" + } + }, + "node_modules/@vercel/static-config/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@vercel/static-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@vitest/expect": { "version": "0.34.6", "dev": true, @@ -45620,6 +46418,21 @@ "dev": true, "license": "MIT" }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "2.0.0", "dev": true, @@ -45991,6 +46804,16 @@ "version": "1.0.1", "license": "MIT" }, + "node_modules/async-listen": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.0.tgz", + "integrity": "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/async-listener": { "version": "0.6.10", "license": "BSD-2-Clause", @@ -46023,6 +46846,13 @@ "retry": "0.13.1" } }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "dev": true, + "license": "MIT" + }, "node_modules/async-stream-emitter": { "version": "4.1.0", "license": "MIT", @@ -49921,22 +50751,6 @@ "node": ">=10" } }, - "node_modules/chromium-edge-launcher/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -50406,6 +51220,13 @@ "node": ">= 0.12.0" } }, + "node_modules/code-block-writer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", + "integrity": "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==", + "dev": true, + "license": "MIT" + }, "node_modules/code-point-at": { "version": "1.1.0", "dev": true, @@ -53498,22 +54319,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/del/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/del/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -54487,6 +55292,112 @@ "integrity": "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q==", "license": "MIT" }, + "node_modules/edge-runtime": { + "version": "2.5.9", + "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.5.9.tgz", + "integrity": "sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@edge-runtime/format": "2.2.1", + "@edge-runtime/ponyfill": "2.4.2", + "@edge-runtime/vm": "3.2.0", + "async-listen": "3.0.1", + "mri": "1.2.0", + "picocolors": "1.0.0", + "pretty-ms": "7.0.1", + "signal-exit": "4.0.2", + "time-span": "4.0.0" + }, + "bin": { + "edge-runtime": "dist/cli/index.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/edge-runtime/node_modules/async-listen": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.1.tgz", + "integrity": "sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/edge-runtime/node_modules/convert-hrtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-3.0.0.tgz", + "integrity": "sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/edge-runtime/node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/edge-runtime/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/edge-runtime/node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/edge-runtime/node_modules/signal-exit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/edge-runtime/node_modules/time-span": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-4.0.0.tgz", + "integrity": "sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/editorconfig": { "version": "1.0.4", "dev": true, @@ -55573,6 +56484,278 @@ "@esbuild/win32-x64": "0.18.20" } }, + "node_modules/esbuild-android-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", + "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", + "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", + "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", + "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", + "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", + "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", + "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", + "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", + "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", + "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", + "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", + "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", + "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", + "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", + "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", + "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/esbuild-plugin-react-virtualized": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/esbuild-plugin-react-virtualized/-/esbuild-plugin-react-virtualized-1.0.4.tgz", @@ -55582,6 +56765,74 @@ "esbuild": "*" } }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", + "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", + "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", + "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", + "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", @@ -59530,20 +60781,6 @@ "node": ">=12.0.0" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/flatted": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", @@ -59974,6 +61211,28 @@ "incremental-encoder": "0.0.1" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/generic-names": { "version": "4.0.0", "dev": true, @@ -63978,6 +65237,15 @@ "version": "1.0.4", "license": "BSD-3-Clause" }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -67834,6 +69102,17 @@ "lodash": "^4.17.4" } }, + "node_modules/json-schema-to-ts": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-1.6.4.tgz", + "integrity": "sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.6", + "ts-toolbelt": "^6.15.5" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "license": "MIT" @@ -69815,59 +71094,6 @@ "node": ">=10" } }, - "node_modules/make-fetch-happen/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/make-fetch-happen/node_modules/semver": { "version": "7.5.4", "dev": true, @@ -77196,20 +78422,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/node-gyp/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/semver": { "version": "7.5.4", "dev": true, @@ -78594,20 +79806,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-check-updates/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/npm-check-updates/node_modules/semver": { "version": "7.5.4", "dev": true, @@ -79065,6 +80263,20 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nssocket": { "version": "0.6.0", "license": "MIT", @@ -83359,6 +84571,21 @@ "dev": true, "license": "MIT" }, + "node_modules/react-chartjs-2": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.10.0.tgz", + "integrity": "sha512-1MjWEkUn8LLFf6GVyYUOrruJTW3yVU5hlEJOwGj3MiokuC+jH/BahjWVGAMonbe9UYbEIUbd2Rn36iVlC0Hb7w==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.19", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "chart.js": "^2.3", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0" + } + }, "node_modules/react-country-flag": { "version": "3.0.2", "license": "MIT", @@ -88073,14 +89300,19 @@ } }, "node_modules/rimraf": { - "version": "3.0.0", - "dev": true, + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "license": "ISC", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ripemd160": { @@ -92206,21 +93438,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/sqlite3/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/sqlite3/node_modules/semver": { "version": "7.6.0", "dev": true, @@ -95615,6 +96832,17 @@ "node": ">=4" } }, + "node_modules/ts-morph": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-12.0.0.tgz", + "integrity": "sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.11.0", + "code-block-writer": "^10.1.1" + } + }, "node_modules/ts-node": { "version": "10.9.1", "license": "MIT", @@ -95990,6 +97218,13 @@ "dev": true, "license": "ISC" }, + "node_modules/ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tsconfck": { "version": "2.1.2", "dev": true, @@ -107172,23 +108407,6 @@ "node": ">=18" } }, - "packages/distro/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "packages/distro/node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", @@ -107427,16 +108645,6 @@ "node": ">=18" } }, - "packages/distro/node_modules/@types/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "packages/distro/node_modules/@types/semver": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", @@ -107902,167 +109110,6 @@ "node": ">=18.0" } }, - "packages/docs/node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "packages/docs/node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "packages/docs/node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "packages/docs/node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/docs/node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "packages/docs/node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -108239,22 +109286,6 @@ "node": ">=18" } }, - "packages/docs/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "packages/docs/node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", @@ -108491,12 +109522,6 @@ "url": "https://paulmillr.com/funding/" } }, - "packages/docs/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "license": "MIT" - }, "packages/docs/node_modules/@scalar/agent-chat": { "version": "0.9.10", "resolved": "https://registry.npmjs.org/@scalar/agent-chat/-/agent-chat-0.9.10.tgz", @@ -109063,26 +110088,6 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, - "packages/docs/node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, "packages/docs/node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -109193,12 +110198,6 @@ "node": ">=6" } }, - "packages/docs/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, "packages/docs/node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -110719,15 +111718,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "packages/docs/node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "packages/docs/node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -110807,15 +111797,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/docs/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "packages/docs/node_modules/send": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", @@ -111747,23 +112728,6 @@ "node": ">=18" } }, - "packages/embed/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "packages/embed/node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", @@ -114005,16 +114969,6 @@ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true }, - "packages/harmony/node_modules/@types/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "packages/harmony/node_modules/@types/react-virtualized": { "version": "9.21.30", "dev": true, @@ -117111,9 +118065,691 @@ "node": ">=10" } }, + "packages/migrate-tool": { + "name": "@audius/migrate-tool", + "version": "0.1.0", + "dependencies": { + "@audius/sdk": "file:../sdk", + "@supabase/supabase-js": "^2.45.0", + "react": "19.0.0", + "react-dom": "19.0.0" + }, + "devDependencies": { + "@types/node": "^22.10.0", + "@types/react": "19.0.0", + "@types/react-dom": "19.0.0", + "@vercel/node": "^3.2.0", + "@vitejs/plugin-react": "^4.2.2", + "buffer": "^6.0.3", + "process": "^0.11.10", + "typescript": "^5.0.4", + "vite": "^6.0.0", + "vite-plugin-node-polyfills": "^0.23.0" + } + }, + "packages/migrate-tool/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/migrate-tool/node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "packages/migrate-tool/node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "packages/migrate-tool/node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "packages/migrate-tool/node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "packages/migrate-tool/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "packages/migrate-tool/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "packages/migrate-tool/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "packages/migrate-tool/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "packages/migrate-tool/node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "packages/migrate-tool/node_modules/vite-plugin-node-polyfills": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.23.0.tgz", + "integrity": "sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, "packages/mobile": { "name": "@audius/mobile", - "version": "1.5.183", + "version": "1.5.184", "dependencies": { "@amplitude/analytics-react-native": "1.4.11", "@audius/common": "*", @@ -120301,23 +121937,6 @@ "node": ">=18" } }, - "packages/protocol-dashboard/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "packages/protocol-dashboard/node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", @@ -120696,16 +122315,6 @@ "integrity": "sha512-Sjsy10w6XFHDktJJdXzBJmoondAKW+LcGpRFH+9+zXEDj0cOH8BxJuZA9vUDSMAzU1YRJlsPKmZEEiTYDlICLw==", "dev": true }, - "packages/protocol-dashboard/node_modules/@types/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "packages/protocol-dashboard/node_modules/@types/react-helmet": { "version": "5.0.16", "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-5.0.16.tgz", @@ -121954,20 +123563,6 @@ "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true }, - "packages/protocol-dashboard/node_modules/react-chartjs-2": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.10.0.tgz", - "integrity": "sha512-1MjWEkUn8LLFf6GVyYUOrruJTW3yVU5hlEJOwGj3MiokuC+jH/BahjWVGAMonbe9UYbEIUbd2Rn36iVlC0Hb7w==", - "dependencies": { - "lodash": "^4.17.19", - "prop-types": "^15.7.2" - }, - "peerDependencies": { - "chart.js": "^2.3", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", - "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0" - } - }, "packages/protocol-dashboard/node_modules/react-markdown": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", @@ -126382,23 +127977,6 @@ "node": ">=18" } }, - "packages/web/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, "packages/web/node_modules/@esbuild/linux-mips64el": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", @@ -127487,16 +129065,6 @@ "dev": true, "license": "MIT" }, - "packages/web/node_modules/@types/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "packages/web/node_modules/@vitejs/plugin-react-swc": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-4.2.2.tgz", diff --git a/packages/migrate-tool/.env.example b/packages/migrate-tool/.env.example new file mode 100644 index 00000000000..b0403e548a0 --- /dev/null +++ b/packages/migrate-tool/.env.example @@ -0,0 +1,25 @@ +# ----- Frontend (Vite — must be prefixed VITE_) ----- + +# Audius developer app API key (safe to expose in browser). +# Get one at audius.co/settings → Developer Apps. +VITE_AUDIUS_API_KEY= + +# "production" (default) or "development" to point at a local protocol stack. +VITE_AUDIUS_ENVIRONMENT=production + +# ----- Backend (Vercel functions — never expose in browser) ----- + +# Audius bearer token. Backend only. Used with the API key above so the +# server can act on behalf of users who have authorized the developer app. +AUDIUS_API_KEY= +AUDIUS_BEARER_TOKEN= + +# Bearer secret that admin endpoints (list/approve/reject) require in the +# Authorization header. Pick a long random string and share it only with +# Audius team members authorized to approve migrations. +ADMIN_BEARER_TOKEN= + +# Supabase connection. The service role key bypasses RLS and must stay +# backend-only — never expose it. +SUPABASE_URL= +SUPABASE_SERVICE_ROLE_KEY= diff --git a/packages/migrate-tool/.gitignore b/packages/migrate-tool/.gitignore new file mode 100644 index 00000000000..913fe16ffb5 --- /dev/null +++ b/packages/migrate-tool/.gitignore @@ -0,0 +1,7 @@ +node_modules +dist +.vercel +.env +.env.local +*.log +.turbo diff --git a/packages/migrate-tool/README.md b/packages/migrate-tool/README.md new file mode 100644 index 00000000000..3fef40ae196 --- /dev/null +++ b/packages/migrate-tool/README.md @@ -0,0 +1,129 @@ +# @audius/migrate-tool + +A small web tool for moving an artist's tracks from an old Audius account to a +new one — for cases where the artist has lost access to their original account +(forgotten password, lost email) and has created a new account. + +Designed to be deployed to **migrate.audius.co** on Vercel with a Supabase +database backing the request queue. + +## How it works + +1. The artist signs in with their new Audius account (OAuth via the Audius + developer app). +2. They enter the handle of their old account. The tool previews the tracks + that would be migrated. +3. They submit a migration request. The request is stored in Supabase with + `status = 'pending'`. +4. An Audius team member opens `/admin`, unlocks with the admin bearer token, + and reviews the request. Identity verification (confirming the requester + actually owns the old account) happens **out-of-band** via the usual + support channel — the tool does not enforce it. +5. On approval the backend pulls each old track's audio + artwork via the SDK + and re-uploads it on the new account using the developer app's bearer + token. Per-track results are written back to the DB and shown on the + status page. + +## Limitations + +- **Audio source selection**: the worker tries sources in priority order + for each track and uses the first one that succeeds: + 1. Raw `orig_file_cid` fetched from the rendezvous-primary validator node + (`/content/{cid}`) — bit-for-bit copy of the original master, + regardless of whether the artist marked the track downloadable. + 2. Same CID, mirror node — covers the case where the primary node is + unhealthy. + 3. Gated download URL — original master, only available when the track + is flagged downloadable. + 4. Transcoded MP3 stream — lossy, but always reachable. Acts as the + last-resort fallback so every approved request gets a content copy. + Sources 1 and 2 are skipped when `orig_file_cid` is missing or + `is_original_available` is false (legacy uploads or pruned originals). +- **No identity verification in-tool**: anyone signed in can request migration + of any handle. The approver is responsible for verifying the requester owns + the old account before approving. Don't approve a request without + confirming identity through a separate channel. +- **Old account is not modified**: the tracks are re-created on the new + account. The originals on the old account are untouched (the tool has no + authority over the old account). +- **No social-graph preservation**: plays, favorites, reposts, and comments + on the old tracks do not carry over. + +## Deploy + +### 1. Supabase + +Create a project, then run the SQL in `supabase/migrations/0001_init.sql`. + +You'll need: + +- `SUPABASE_URL` — project URL +- `SUPABASE_SERVICE_ROLE_KEY` — backend-only key (do not expose to the browser) + +### 2. Audius developer app + +Create a developer app at → Developer Apps. You'll +get an **API Key** and a **Bearer Token**. + +- `VITE_AUDIUS_API_KEY` — the API key (safe in the browser; baked into the build) +- `AUDIUS_API_KEY` — same API key, for the backend +- `AUDIUS_BEARER_TOKEN` — backend-only; grants the app permission to act on + behalf of users who have authorized it via OAuth + +You'll also need to whitelist the deployment's OAuth redirect URI in the dev +app's settings (e.g. `https://migrate.audius.co/`). + +### 3. Admin token + +- `ADMIN_BEARER_TOKEN` — pick a long random string. Share it only with team + members authorized to approve migrations. + +### 4. Vercel + +```sh +cd packages/migrate-tool +npx vercel link +npx vercel env add VITE_AUDIUS_API_KEY +npx vercel env add AUDIUS_API_KEY +npx vercel env add AUDIUS_BEARER_TOKEN +npx vercel env add ADMIN_BEARER_TOKEN +npx vercel env add SUPABASE_URL +npx vercel env add SUPABASE_SERVICE_ROLE_KEY +npx vercel --prod +``` + +Then add `migrate.audius.co` as a domain in the Vercel project. + +## Local development + +```sh +cp .env.example .env.local +# Fill in the values, then: +npm install +npm run dev +``` + +The Vite dev server runs at `http://localhost:5180`. To exercise the API +functions locally, run them with `npx vercel dev` instead. + +## Approving a request + +1. Go to `https://migrate.audius.co/admin`. +2. Paste the `ADMIN_BEARER_TOKEN` to unlock. +3. Review the request — especially the old handle and the track list. +4. **Verify the requester owns the old account through your usual support + channel.** This is the only safeguard against migration abuse. +5. Click **Approve & execute**. The backend runs the migration synchronously + (Vercel function timeout is set to 5 minutes in `vercel.json`). + +## Files + +- `src/` — Vite + React SPA (home / status / admin pages) +- `api/` — Vercel serverless functions + - `api/requests/index.ts` — `POST /api/requests` (create) + - `api/requests/[id].ts` — `GET /api/requests/:id` (status) + - `api/admin/requests.ts` — `GET /api/admin/requests` (list, bearer-gated) + - `api/admin/approve.ts` — `POST /api/admin/approve?id=…` (bearer-gated) + - `api/admin/reject.ts` — `POST /api/admin/reject?id=…` (bearer-gated) + - `api/_lib/migrate.ts` — migration worker +- `supabase/migrations/0001_init.sql` — DB schema diff --git a/packages/migrate-tool/api/_lib/audius.ts b/packages/migrate-tool/api/_lib/audius.ts new file mode 100644 index 00000000000..62da71f84cd --- /dev/null +++ b/packages/migrate-tool/api/_lib/audius.ts @@ -0,0 +1,37 @@ +import { + createSdkWithServices, + type AudiusSdkWithServices +} from '@audius/sdk' + +let serverSdk: AudiusSdkWithServices | null = null + +/** + * Server-side SDK initialized with the developer app's API key + bearer + * token. The bearer token grants the app permission to act on behalf of + * any user who has authorized it via OAuth. + * + * Per the SDK README: "Bearer Token — backend only. Grants your app the + * ability to act on behalf of users who have authorized it. Never expose + * this in browser or mobile code." + * + * We use createSdkWithServices (rather than the public sdk() factory) so + * sdk.tracks is the wrapped TracksApi with friendly helpers like + * getTrackStreamUrl, getTrackDownloadUrl, and the createTrack overload + * that handles audio + image upload + trackCid in one call. + */ +export function getServerSDK(): AudiusSdkWithServices { + if (serverSdk) return serverSdk + const apiKey = process.env.AUDIUS_API_KEY + const bearerToken = process.env.AUDIUS_BEARER_TOKEN + if (!apiKey || !bearerToken) { + throw new Error( + 'AUDIUS_API_KEY and AUDIUS_BEARER_TOKEN must be set on the server.' + ) + } + serverSdk = createSdkWithServices({ + apiKey, + bearerToken, + appName: 'AudiusTrackMigration' + }) + return serverSdk +} diff --git a/packages/migrate-tool/api/_lib/auth.ts b/packages/migrate-tool/api/_lib/auth.ts new file mode 100644 index 00000000000..576b4535a9a --- /dev/null +++ b/packages/migrate-tool/api/_lib/auth.ts @@ -0,0 +1,34 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +/** + * Constant-time check that the incoming Authorization header matches the + * admin bearer token. Returns true if authorized, otherwise writes a 401 + * response and returns false — callers can early-return. + */ +export function requireAdmin( + req: VercelRequest, + res: VercelResponse +): boolean { + const expected = process.env.ADMIN_BEARER_TOKEN + if (!expected) { + res.status(500).json({ error: 'ADMIN_BEARER_TOKEN not configured.' }) + return false + } + const header = req.headers.authorization ?? '' + const match = /^Bearer\s+(.+)$/.exec(header) + const token = match?.[1] ?? '' + if (!constantTimeEquals(token, expected)) { + res.status(401).json({ error: 'Unauthorized.' }) + return false + } + return true +} + +function constantTimeEquals(a: string, b: string): boolean { + if (a.length !== b.length) return false + let mismatch = 0 + for (let i = 0; i < a.length; i++) { + mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i) + } + return mismatch === 0 +} diff --git a/packages/migrate-tool/api/_lib/migrate.ts b/packages/migrate-tool/api/_lib/migrate.ts new file mode 100644 index 00000000000..4506bd511cf --- /dev/null +++ b/packages/migrate-tool/api/_lib/migrate.ts @@ -0,0 +1,247 @@ +import type { AudiusSdkWithServices, Genre, Mood, Track } from '@audius/sdk' + +import { getServerSDK } from './audius' +import { getSupabase, TABLE } from './supabase' +import type { DbRow, TrackResult } from './types' + +/** + * Fetch a URL into a Blob with a reasonable timeout. Used for pulling the + * old track's audio and artwork before re-uploading them to the new owner. + */ +async function fetchBlob(url: string, timeoutMs = 90_000): Promise { + const controller = new AbortController() + const timer = setTimeout(() => controller.abort(), timeoutMs) + try { + const res = await fetch(url, { signal: controller.signal }) + if (!res.ok) throw new Error(`Fetch ${res.status} ${res.statusText} (${url})`) + return await res.blob() + } finally { + clearTimeout(timer) + } +} + +function filenameFromUrl(url: string, fallback: string): string { + try { + const u = new URL(url) + const last = u.pathname.split('/').filter(Boolean).pop() + return last || fallback + } catch { + return fallback + } +} + +function blobToFile(blob: Blob, name: string): File { + return new File([blob], name, { type: blob.type || 'application/octet-stream' }) +} + +type AudioCandidate = { + label: string + resolve: () => Promise<{ url: string; filename: string }> +} + +/** + * Build a prioritized list of source URLs for the track's audio. Each + * candidate is tried in order, so a hard failure on the original (pruned + * bytes, unhealthy node, missing index) silently falls through to the + * next best source. The MP3 stream is always last so every track ends up + * with at least *some* content copy. + */ +function buildAudioCandidates( + sdk: AudiusSdkWithServices, + track: Track, + trackId: string, + isDownloadablePreview: boolean +): AudioCandidate[] { + const candidates: AudioCandidate[] = [] + + // 1. Original master via raw CID. Validator nodes serve content-addressed + // files at /content/{cid} with no gating, so this works regardless of + // isDownloadable. Tried first because it's a bit-for-bit copy. + if (track.origFileCid && track.isOriginalAvailable !== false) { + const cid = track.origFileCid + candidates.push({ + label: `orig-cid:${cid}`, + resolve: async () => { + const nodes = sdk.services.storageNodeSelector.getNodes(cid) + if (nodes.length === 0) { + throw new Error('No storage node available for original file CID.') + } + // Pick the rendezvous-primary; the mirror candidate below handles + // failover when this fetch throws. + return { + url: `${nodes[0]}/content/${cid}`, + filename: track.origFilename ?? cid + } + } + }) + + // Same CID, mirrors. Each mirror becomes its own candidate so a single + // unhealthy node doesn't take down the migration. + candidates.push({ + label: `orig-cid-mirrors:${cid}`, + resolve: async () => { + const nodes = sdk.services.storageNodeSelector.getNodes(cid) + const mirror = nodes[1] ?? nodes[2] + if (!mirror) { + throw new Error('No mirror available for original file CID.') + } + return { + url: `${mirror}/content/${cid}`, + filename: track.origFilename ?? cid + } + } + }) + } + + // 2. Gated download URL — only works for tracks the artist flagged as + // downloadable, but the bytes are still the original master. + if (isDownloadablePreview) { + candidates.push({ + label: 'download-url', + resolve: async () => { + const url = await sdk.tracks.getTrackDownloadUrl({ trackId }) + return { url, filename: filenameFromUrl(url, `${trackId}.audio`) } + } + }) + } + + // 3. Transcoded MP3 stream — always available, lossy. Ensures every + // track migrates with *something* even if the original is gone. + candidates.push({ + label: 'stream-url', + resolve: async () => { + const url = await sdk.tracks.getTrackStreamUrl({ trackId }) + return { url, filename: filenameFromUrl(url, `${trackId}.mp3`) } + } + }) + + return candidates +} + +async function fetchAudio( + candidates: AudioCandidate[] +): Promise<{ blob: Blob; filename: string; source: string }> { + const errors: string[] = [] + for (const candidate of candidates) { + try { + const { url, filename } = await candidate.resolve() + const blob = await fetchBlob(url) + return { blob, filename, source: candidate.label } + } catch (e) { + errors.push(`${candidate.label}: ${e instanceof Error ? e.message : String(e)}`) + } + } + throw new Error(`No audio source succeeded. Tried: ${errors.join(' | ')}`) +} + +/** + * Run the migration for one DB row. Updates the row in-place with per-track + * results as it goes, and sets the final status when done. + * + * Audio source order (see buildAudioCandidates): the original master via + * raw CID, then mirrors, then the gated download URL (downloadable tracks + * only), then the transcoded MP3 stream. Each candidate is tried until + * one succeeds — guarantees every track migrates with the highest-fidelity + * copy that's still reachable. + */ +export async function executeMigration(row: DbRow): Promise { + const supabase = getSupabase() + const sdk = getServerSDK() + + await supabase + .from(TABLE) + .update({ status: 'running' }) + .eq('id', row.id) + + const results: TrackResult[] = row.tracks.map((t) => ({ + oldTrackId: t.trackId, + status: 'pending' + })) + + const persistResults = async () => { + await supabase + .from(TABLE) + .update({ results }) + .eq('id', row.id) + } + + let anyFailed = false + + for (let i = 0; i < row.tracks.length; i++) { + const preview = row.tracks[i]! + try { + const trackRes = await sdk.tracks.getTrack({ trackId: preview.trackId }) + const track = trackRes.data + if (!track) throw new Error('Track not found on source account.') + + const candidates = buildAudioCandidates( + sdk, + track, + preview.trackId, + preview.isDownloadable + ) + const { blob: audioBlob, filename: audioFilename } = + await fetchAudio(candidates) + const audioFile = blobToFile(audioBlob, audioFilename) + + let imageFile: File | undefined + const artworkUrl = + track.artwork?._1000x1000 ?? + track.artwork?._480x480 ?? + track.artwork?._150x150 + if (artworkUrl) { + const imageBlob = await fetchBlob(artworkUrl) + imageFile = blobToFile( + imageBlob, + filenameFromUrl(artworkUrl, 'artwork.jpg') + ) + } + + const upload = await sdk.tracks.createTrack({ + userId: row.new_user_id, + audioFile, + imageFile, + // The generated type requires trackCid here, but the wrapped + // createTrack populates it from the audio upload response. See + // TracksApi.createTrack → populateTrackMetadataWithUploadResponseV2. + // @ts-expect-error trackCid is set by the SDK after audio upload + metadata: { + title: track.title, + genre: track.genre as Genre, + description: track.description ?? undefined, + mood: (track.mood as Mood | undefined) ?? undefined, + tags: track.tags ?? undefined, + isrc: track.isrc ?? undefined, + iswc: track.iswc ?? undefined, + license: track.license ?? undefined + } + }) + + results[i] = { + oldTrackId: preview.trackId, + newTrackId: upload.trackId, + status: 'success' + } + } catch (e) { + anyFailed = true + results[i] = { + oldTrackId: preview.trackId, + status: 'failed', + error: e instanceof Error ? e.message : String(e) + } + } + await persistResults() + } + + await supabase + .from(TABLE) + .update({ + status: anyFailed ? 'failed' : 'completed', + results, + completed_at: new Date().toISOString(), + failure_reason: anyFailed + ? 'One or more tracks failed to migrate. See per-track results.' + : null + }) + .eq('id', row.id) +} diff --git a/packages/migrate-tool/api/_lib/serialize.ts b/packages/migrate-tool/api/_lib/serialize.ts new file mode 100644 index 00000000000..5a3c0239936 --- /dev/null +++ b/packages/migrate-tool/api/_lib/serialize.ts @@ -0,0 +1,18 @@ +import type { DbRow } from './types' + +export function rowToResponse(row: DbRow) { + return { + id: row.id, + newUserId: row.new_user_id, + newUserHandle: row.new_user_handle, + oldHandle: row.old_handle, + status: row.status, + tracks: row.tracks, + results: row.results ?? [], + rejectionReason: row.rejection_reason, + failureReason: row.failure_reason, + createdAt: row.created_at, + approvedAt: row.approved_at, + completedAt: row.completed_at + } +} diff --git a/packages/migrate-tool/api/_lib/supabase.ts b/packages/migrate-tool/api/_lib/supabase.ts new file mode 100644 index 00000000000..d73bb00db77 --- /dev/null +++ b/packages/migrate-tool/api/_lib/supabase.ts @@ -0,0 +1,20 @@ +import { createClient, type SupabaseClient } from '@supabase/supabase-js' + +let client: SupabaseClient | null = null + +export function getSupabase(): SupabaseClient { + if (client) return client + const url = process.env.SUPABASE_URL + const key = process.env.SUPABASE_SERVICE_ROLE_KEY + if (!url || !key) { + throw new Error( + 'SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set on the server.' + ) + } + client = createClient(url, key, { + auth: { persistSession: false, autoRefreshToken: false } + }) + return client +} + +export const TABLE = 'migration_requests' diff --git a/packages/migrate-tool/api/_lib/types.ts b/packages/migrate-tool/api/_lib/types.ts new file mode 100644 index 00000000000..90e7647a57f --- /dev/null +++ b/packages/migrate-tool/api/_lib/types.ts @@ -0,0 +1,39 @@ +export type RequestStatus = + | 'pending' + | 'approved' + | 'running' + | 'completed' + | 'failed' + | 'rejected' + +export type TrackPreview = { + trackId: string + title: string + genre?: string | null + durationSec?: number | null + artworkUrl?: string | null + isDownloadable: boolean + hasOriginal: boolean +} + +export type TrackResult = { + oldTrackId: string + newTrackId?: string + status: 'pending' | 'success' | 'failed' + error?: string +} + +export type DbRow = { + id: string + new_user_id: string + new_user_handle: string + old_handle: string + status: RequestStatus + tracks: TrackPreview[] + results: TrackResult[] | null + rejection_reason: string | null + failure_reason: string | null + created_at: string + approved_at: string | null + completed_at: string | null +} diff --git a/packages/migrate-tool/api/admin/approve.ts b/packages/migrate-tool/api/admin/approve.ts new file mode 100644 index 00000000000..f73143f2332 --- /dev/null +++ b/packages/migrate-tool/api/admin/approve.ts @@ -0,0 +1,64 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +import { requireAdmin } from '../_lib/auth' +import { executeMigration } from '../_lib/migrate' +import { getSupabase, TABLE } from '../_lib/supabase' +import type { DbRow } from '../_lib/types' + +export default async function handler(req: VercelRequest, res: VercelResponse) { + if (req.method !== 'POST') { + res.setHeader('Allow', 'POST') + res.status(405).json({ error: 'Method not allowed' }) + return + } + if (!requireAdmin(req, res)) return + + const id = String(req.query.id ?? '').trim() + if (!id) { + res.status(400).json({ error: 'id is required.' }) + return + } + + const supabase = getSupabase() + + // Conditionally flip pending → approved so a double-approval is a no-op. + const { data: claimed, error: claimError } = await supabase + .from(TABLE) + .update({ + status: 'approved', + approved_at: new Date().toISOString() + }) + .eq('id', id) + .eq('status', 'pending') + .select('*') + .maybeSingle() + + if (claimError) { + res.status(500).json({ error: claimError.message }) + return + } + if (!claimed) { + res.status(409).json({ error: 'Request is not pending.' }) + return + } + + try { + await executeMigration(claimed) + } catch (e) { + await supabase + .from(TABLE) + .update({ + status: 'failed', + failure_reason: e instanceof Error ? e.message : String(e), + completed_at: new Date().toISOString() + }) + .eq('id', id) + res.status(500).json({ + error: 'Migration failed.', + message: e instanceof Error ? e.message : String(e) + }) + return + } + + res.status(200).json({ ok: true }) +} diff --git a/packages/migrate-tool/api/admin/reject.ts b/packages/migrate-tool/api/admin/reject.ts new file mode 100644 index 00000000000..2beb4b00dae --- /dev/null +++ b/packages/migrate-tool/api/admin/reject.ts @@ -0,0 +1,39 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +import { requireAdmin } from '../_lib/auth' +import { getSupabase, TABLE } from '../_lib/supabase' + +export default async function handler(req: VercelRequest, res: VercelResponse) { + if (req.method !== 'POST') { + res.setHeader('Allow', 'POST') + res.status(405).json({ error: 'Method not allowed' }) + return + } + if (!requireAdmin(req, res)) return + + const id = String(req.query.id ?? '').trim() + if (!id) { + res.status(400).json({ error: 'id is required.' }) + return + } + + const body = (req.body ?? {}) as { reason?: string } + const reason = String(body.reason ?? '').trim() || null + + const supabase = getSupabase() + const { error } = await supabase + .from(TABLE) + .update({ + status: 'rejected', + rejection_reason: reason + }) + .eq('id', id) + .eq('status', 'pending') + + if (error) { + res.status(500).json({ error: error.message }) + return + } + + res.status(200).json({ ok: true }) +} diff --git a/packages/migrate-tool/api/admin/requests.ts b/packages/migrate-tool/api/admin/requests.ts new file mode 100644 index 00000000000..acc0c536e01 --- /dev/null +++ b/packages/migrate-tool/api/admin/requests.ts @@ -0,0 +1,31 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +import { requireAdmin } from '../_lib/auth' +import { rowToResponse } from '../_lib/serialize' +import { getSupabase, TABLE } from '../_lib/supabase' +import type { DbRow } from '../_lib/types' + +export default async function handler(req: VercelRequest, res: VercelResponse) { + if (req.method !== 'GET') { + res.setHeader('Allow', 'GET') + res.status(405).json({ error: 'Method not allowed' }) + return + } + if (!requireAdmin(req, res)) return + + const supabase = getSupabase() + const { data, error } = await supabase + .from(TABLE) + .select('*') + .order('created_at', { ascending: false }) + .limit(200) + + if (error) { + res.status(500).json({ error: error.message }) + return + } + + res.status(200).json({ + requests: ((data ?? []) as DbRow[]).map(rowToResponse) + }) +} diff --git a/packages/migrate-tool/api/requests/[id].ts b/packages/migrate-tool/api/requests/[id].ts new file mode 100644 index 00000000000..a391540e4d9 --- /dev/null +++ b/packages/migrate-tool/api/requests/[id].ts @@ -0,0 +1,37 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +import { rowToResponse } from '../_lib/serialize' +import { getSupabase, TABLE } from '../_lib/supabase' +import type { DbRow } from '../_lib/types' + +export default async function handler(req: VercelRequest, res: VercelResponse) { + if (req.method !== 'GET') { + res.setHeader('Allow', 'GET') + res.status(405).json({ error: 'Method not allowed' }) + return + } + + const id = String(req.query.id ?? '').trim() + if (!id) { + res.status(400).json({ error: 'id is required.' }) + return + } + + const supabase = getSupabase() + const { data, error } = await supabase + .from(TABLE) + .select('*') + .eq('id', id) + .maybeSingle() + + if (error) { + res.status(500).json({ error: error.message }) + return + } + if (!data) { + res.status(404).json({ error: 'Request not found.' }) + return + } + + res.status(200).json(rowToResponse(data)) +} diff --git a/packages/migrate-tool/api/requests/index.ts b/packages/migrate-tool/api/requests/index.ts new file mode 100644 index 00000000000..b1f19204381 --- /dev/null +++ b/packages/migrate-tool/api/requests/index.ts @@ -0,0 +1,52 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node' + +import { getSupabase, TABLE } from '../_lib/supabase' +import type { TrackPreview } from '../_lib/types' + +type Body = { + newUserId?: string + newUserHandle?: string + oldHandle?: string + tracks?: TrackPreview[] +} + +export default async function handler(req: VercelRequest, res: VercelResponse) { + if (req.method !== 'POST') { + res.setHeader('Allow', 'POST') + res.status(405).json({ error: 'Method not allowed' }) + return + } + + const body = (req.body ?? {}) as Body + const newUserId = String(body.newUserId ?? '').trim() + const newUserHandle = String(body.newUserHandle ?? '').trim() + const oldHandle = String(body.oldHandle ?? '').trim().replace(/^@/, '') + const tracks = Array.isArray(body.tracks) ? body.tracks : [] + + if (!newUserId || !newUserHandle || !oldHandle || tracks.length === 0) { + res.status(400).json({ + error: 'newUserId, newUserHandle, oldHandle, and tracks are required.' + }) + return + } + + const supabase = getSupabase() + const { data, error } = await supabase + .from(TABLE) + .insert({ + new_user_id: newUserId, + new_user_handle: newUserHandle, + old_handle: oldHandle, + tracks, + status: 'pending' + }) + .select('id') + .single() + + if (error || !data) { + res.status(500).json({ error: error?.message ?? 'Insert failed.' }) + return + } + + res.status(201).json({ id: data.id }) +} diff --git a/packages/migrate-tool/index.html b/packages/migrate-tool/index.html new file mode 100644 index 00000000000..152560ef2de --- /dev/null +++ b/packages/migrate-tool/index.html @@ -0,0 +1,12 @@ + + + + + + Audius Track Migration + + +
+ + + diff --git a/packages/migrate-tool/package.json b/packages/migrate-tool/package.json new file mode 100644 index 00000000000..d22888023fa --- /dev/null +++ b/packages/migrate-tool/package.json @@ -0,0 +1,33 @@ +{ + "name": "@audius/migrate-tool", + "version": "0.1.0", + "private": true, + "type": "module", + "description": "Track migration tool — moves an artist's tracks from an old Audius account to a new one. Designed to be deployed to migrate.audius.co.", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview", + "typecheck": "tsc -b --noEmit", + "lint": "echo 'no lint configured yet'", + "verify": "npm run typecheck" + }, + "dependencies": { + "@audius/sdk": "file:../sdk", + "@supabase/supabase-js": "^2.45.0", + "react": "19.0.0", + "react-dom": "19.0.0" + }, + "devDependencies": { + "@types/node": "^22.10.0", + "@types/react": "19.0.0", + "@types/react-dom": "19.0.0", + "@vercel/node": "^3.2.0", + "@vitejs/plugin-react": "^4.2.2", + "buffer": "^6.0.3", + "process": "^0.11.10", + "typescript": "^5.0.4", + "vite": "^6.0.0", + "vite-plugin-node-polyfills": "^0.23.0" + } +} diff --git a/packages/migrate-tool/src/App.tsx b/packages/migrate-tool/src/App.tsx new file mode 100644 index 00000000000..d051ddc971e --- /dev/null +++ b/packages/migrate-tool/src/App.tsx @@ -0,0 +1,67 @@ +import { useEffect, useState } from 'react' + +import { Admin } from './pages/Admin' +import { Home } from './pages/Home' +import { Status } from './pages/Status' + +type Route = + | { page: 'home' } + | { page: 'status'; requestId: string } + | { page: 'admin' } + +function parseRoute(): Route { + const url = new URL(window.location.href) + if (url.pathname.startsWith('/admin')) return { page: 'admin' } + if (url.pathname.startsWith('/status')) { + return { page: 'status', requestId: url.searchParams.get('id') ?? '' } + } + return { page: 'home' } +} + +export function App() { + const [route, setRoute] = useState(() => parseRoute()) + + useEffect(() => { + const handler = () => setRoute(parseRoute()) + window.addEventListener('popstate', handler) + return () => window.removeEventListener('popstate', handler) + }, []) + + const navigate = (path: string) => { + window.history.pushState({}, '', path) + setRoute(parseRoute()) + } + + return ( +
+
+

+ { e.preventDefault(); navigate('/') }}> + Audius Track Migration + +

+

+ Move tracks from an old Audius account to a new one. Each migration + requires approval from an Audius team member. +

+
+ +
+ {route.page === 'home' && } + {route.page === 'status' && ( + + )} + {route.page === 'admin' && } +
+ + +
+ ) +} diff --git a/packages/migrate-tool/src/config.ts b/packages/migrate-tool/src/config.ts new file mode 100644 index 00000000000..905fb375508 --- /dev/null +++ b/packages/migrate-tool/src/config.ts @@ -0,0 +1,17 @@ +const apiKey = + typeof import.meta !== 'undefined' && + import.meta.env?.VITE_AUDIUS_API_KEY != null + ? String(import.meta.env.VITE_AUDIUS_API_KEY).trim() + : undefined + +const environment = + typeof import.meta !== 'undefined' && + import.meta.env?.VITE_AUDIUS_ENVIRONMENT === 'development' + ? ('development' as const) + : ('production' as const) + +export const config = { + apiKey, + environment, + isConfigured: Boolean(apiKey) +} diff --git a/packages/migrate-tool/src/main.tsx b/packages/migrate-tool/src/main.tsx new file mode 100644 index 00000000000..12ab679c9fc --- /dev/null +++ b/packages/migrate-tool/src/main.tsx @@ -0,0 +1,14 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' + +import { App } from './App' +import './styles.css' + +const root = document.getElementById('root') +if (!root) throw new Error('Missing #root element') + +createRoot(root).render( + + + +) diff --git a/packages/migrate-tool/src/pages/Admin.tsx b/packages/migrate-tool/src/pages/Admin.tsx new file mode 100644 index 00000000000..49bb50c5dca --- /dev/null +++ b/packages/migrate-tool/src/pages/Admin.tsx @@ -0,0 +1,211 @@ +import { useCallback, useEffect, useState } from 'react' + +import type { MigrationRequest } from '../types' + +const TOKEN_STORAGE_KEY = 'audius-migrate-admin-token' + +export function Admin() { + const [token, setToken] = useState( + () => sessionStorage.getItem(TOKEN_STORAGE_KEY) ?? '' + ) + const [authenticated, setAuthenticated] = useState(false) + const [requests, setRequests] = useState(null) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const [busyId, setBusyId] = useState(null) + + const fetchList = useCallback( + async (bearerToken: string) => { + setLoading(true) + setError(null) + try { + const res = await fetch('/api/admin/requests', { + headers: { Authorization: `Bearer ${bearerToken}` } + }) + if (res.status === 401) { + throw new Error('Invalid admin token.') + } + if (!res.ok) { + throw new Error(`Server returned ${res.status}`) + } + const body = (await res.json()) as { requests: MigrationRequest[] } + setRequests(body.requests) + setAuthenticated(true) + sessionStorage.setItem(TOKEN_STORAGE_KEY, bearerToken) + } catch (e) { + setError(e instanceof Error ? e.message : 'Failed to load.') + setAuthenticated(false) + } finally { + setLoading(false) + } + }, + [] + ) + + useEffect(() => { + if (token) fetchList(token) + // Run once on mount with the persisted token (if any). Subsequent + // refreshes happen through the explicit "Refresh" button. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const handleUnlock = useCallback( + (e: React.FormEvent) => { + e.preventDefault() + fetchList(token) + }, + [token, fetchList] + ) + + const handleApprove = useCallback( + async (id: string) => { + if (!confirm('Approve this migration? The tracks will be re-uploaded on the new account.')) return + setBusyId(id) + try { + const res = await fetch( + `/api/admin/approve?id=${encodeURIComponent(id)}`, + { method: 'POST', headers: { Authorization: `Bearer ${token}` } } + ) + if (!res.ok) throw new Error(`Approve failed: ${res.status}`) + await fetchList(token) + } catch (e) { + setError(e instanceof Error ? e.message : 'Approve failed.') + } finally { + setBusyId(null) + } + }, + [token, fetchList] + ) + + const handleReject = useCallback( + async (id: string) => { + const reason = prompt('Rejection reason (shown to the requester):') + if (reason == null) return + setBusyId(id) + try { + const res = await fetch( + `/api/admin/reject?id=${encodeURIComponent(id)}`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ reason }) + } + ) + if (!res.ok) throw new Error(`Reject failed: ${res.status}`) + await fetchList(token) + } catch (e) { + setError(e instanceof Error ? e.message : 'Reject failed.') + } finally { + setBusyId(null) + } + }, + [token, fetchList] + ) + + if (!authenticated) { + return ( +
+

Admin

+ {error &&
{error}
} +
+ + setToken(e.target.value)} + autoComplete="off" + /> +
+ +
+
+
+ ) + } + + return ( + <> + {error &&
{error}
} +
+
+

Requests

+ +
+
+ + {(requests ?? []).length === 0 && ( +
No requests yet.
+ )} + + {(requests ?? []).map((req) => ( +
+
+
+
+ @{req.oldHandle} → @{req.newUserHandle} +
+
+ {req.tracks.length} track{req.tracks.length === 1 ? '' : 's'} + {' · '} + {req.id} + {' · '} + {new Date(req.createdAt).toLocaleString()} +
+
+ {req.status} +
+ +
    + {req.tracks.slice(0, 5).map((t) => ( +
  • + {t.artworkUrl ? ( + + ) : ( +
    + )} +
    +
    {t.title}
    +
    + {t.genre ?? 'Unknown'} + {' · '} + {t.hasOriginal ? 'original audio' : 'mp3 only'} +
    +
    +
  • + ))} + {req.tracks.length > 5 && ( +
  • …and {req.tracks.length - 5} more
  • + )} +
+ + {req.status === 'pending' && ( +
+ + +
+ )} +
+ ))} + + ) +} diff --git a/packages/migrate-tool/src/pages/Home.tsx b/packages/migrate-tool/src/pages/Home.tsx new file mode 100644 index 00000000000..44bd6bb4328 --- /dev/null +++ b/packages/migrate-tool/src/pages/Home.tsx @@ -0,0 +1,257 @@ +import { useCallback, useEffect, useState } from 'react' + +import type { User } from '@audius/sdk' + +import { config } from '../config' +import { getSDK } from '../sdk' +import type { TrackPreview } from '../types' + +type Props = { + navigate: (path: string) => void +} + +async function formatApiError(reason: unknown): Promise { + if (reason != null && typeof reason === 'object' && 'response' in reason) { + const res = (reason as { response: Response }).response + if (res != null && typeof res.text === 'function') { + try { + const body = await res.text() + return `API ${res.status}: ${body || res.statusText || 'Unknown'}` + } catch { + return `API ${res.status}` + } + } + } + return reason instanceof Error ? reason.message : 'Request failed' +} + +export function Home({ navigate }: Props) { + const [profile, setProfile] = useState(null) + const [oldHandle, setOldHandle] = useState('') + const [tracks, setTracks] = useState(null) + const [loading, setLoading] = useState(false) + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + const sdkInstance = getSDK() + + if (sdkInstance.oauth.hasRedirectResult()) { + setLoading(true) + sdkInstance.oauth + .handleRedirect() + .then(() => sdkInstance.oauth.getUser()) + .then((user) => setProfile(user)) + .catch(async (e) => setError(await formatApiError(e))) + .finally(() => setLoading(false)) + return + } + + sdkInstance.oauth.isAuthenticated().then((authenticated) => { + if (!authenticated) return + sdkInstance.oauth + .getUser() + .then((user) => setProfile(user)) + .catch(() => { + // expired session — fall back to sign-in screen + }) + }) + }, []) + + const handleSignIn = useCallback(async () => { + setError(null) + setLoading(true) + try { + const sdkInstance = getSDK() + await sdkInstance.oauth.login({ scope: 'write', display: 'popup' }) + const user = await sdkInstance.oauth.getUser() + setProfile(user) + } catch (e) { + setError(await formatApiError(e)) + } finally { + setLoading(false) + } + }, []) + + const handleSignOut = useCallback(async () => { + await getSDK().oauth.logout() + setProfile(null) + setTracks(null) + setOldHandle('') + }, []) + + const handlePreview = useCallback(async () => { + setError(null) + setTracks(null) + const handle = oldHandle.trim().replace(/^@/, '') + if (!handle) { + setError('Enter the old account handle.') + return + } + setLoading(true) + try { + const sdkInstance = getSDK() + const res = await sdkInstance.users.getTracksByUserHandle({ + handle, + limit: 100 + }) + const data = res.data ?? [] + const previews: TrackPreview[] = data.map((t) => ({ + trackId: t.id, + title: t.title, + genre: t.genre ?? null, + durationSec: t.duration ?? null, + artworkUrl: t.artwork?._150x150 ?? t.artwork?._480x480 ?? null, + isDownloadable: Boolean(t.isDownloadable), + hasOriginal: Boolean(t.origFileCid) && t.isOriginalAvailable !== false + })) + if (previews.length === 0) { + setError(`No tracks found for @${handle}.`) + } + setTracks(previews) + } catch (e) { + setError(await formatApiError(e)) + } finally { + setLoading(false) + } + }, [oldHandle]) + + const handleSubmit = useCallback(async () => { + if (!profile || !tracks || tracks.length === 0) return + setSubmitting(true) + setError(null) + try { + const res = await fetch('/api/requests', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + newUserId: profile.id, + newUserHandle: profile.handle, + oldHandle: oldHandle.trim().replace(/^@/, ''), + tracks + }) + }) + if (!res.ok) { + throw new Error(`Server returned ${res.status}: ${await res.text()}`) + } + const body = (await res.json()) as { id: string } + navigate(`/status?id=${encodeURIComponent(body.id)}`) + } catch (e) { + setError(e instanceof Error ? e.message : 'Submission failed.') + } finally { + setSubmitting(false) + } + }, [profile, tracks, oldHandle, navigate]) + + if (!config.isConfigured) { + return ( +
+

Setup required

+

+ VITE_AUDIUS_API_KEY is not set. Create an Audius + developer app at + audius.co/settings → Developer Apps and add the key to your + environment. +

+
+ ) + } + + return ( + <> + {error &&
{error}
} + +
+

Step 1 — Sign in with your new account

+ {profile ? ( +
+
+ Signed in as @{profile.handle} +
+ user_id: {profile.id} +
+
+ +
+ ) : ( + + )} +
+ + {profile && ( +
+

Step 2 — Old account handle

+

+ The handle of the account whose tracks you want migrated. +

+ + setOldHandle(e.target.value)} + disabled={loading || submitting} + /> +
+ +
+
+ )} + + {tracks && tracks.length > 0 && ( +
+

Step 3 — Review & submit

+
+ Heads up: the worker migrates the original + uploaded master whenever it's still on the network, regardless + of whether the track is marked downloadable. The few tracks + tagged below as mp3 only have no original on file and + will migrate with the transcoded MP3 stream. +
+

+ {tracks.length} track{tracks.length === 1 ? '' : 's'} will be + re-created on @{profile?.handle} once an Audius team member + approves this request. +

+
    + {tracks.map((t) => ( +
  • + {t.artworkUrl ? ( + + ) : ( +
    + )} +
    +
    {t.title}
    +
    + {t.genre ?? 'Unknown genre'} + {' · '} + {t.hasOriginal ? 'original audio' : 'mp3 only'} +
    +
    +
  • + ))} +
+
+ +
+
+ )} + + ) +} diff --git a/packages/migrate-tool/src/pages/Status.tsx b/packages/migrate-tool/src/pages/Status.tsx new file mode 100644 index 00000000000..731cd84383a --- /dev/null +++ b/packages/migrate-tool/src/pages/Status.tsx @@ -0,0 +1,168 @@ +import { useEffect, useState } from 'react' + +import type { MigrationRequest } from '../types' + +type Props = { + requestId: string + navigate: (path: string) => void +} + +const POLL_INTERVAL_MS = 5000 + +export function Status({ requestId, navigate }: Props) { + const [request, setRequest] = useState(null) + const [error, setError] = useState(null) + + useEffect(() => { + if (!requestId) return + let cancelled = false + + const load = async () => { + try { + const res = await fetch( + `/api/requests/${encodeURIComponent(requestId)}` + ) + if (!res.ok) { + throw new Error(`Server returned ${res.status}`) + } + const body = (await res.json()) as MigrationRequest + if (!cancelled) { + setRequest(body) + setError(null) + } + } catch (e) { + if (!cancelled) { + setError(e instanceof Error ? e.message : 'Failed to load.') + } + } + } + + load() + const id = setInterval(load, POLL_INTERVAL_MS) + return () => { + cancelled = true + clearInterval(id) + } + }, [requestId]) + + if (!requestId) { + return ( +
+

Missing request id

+ +
+ ) + } + + if (error && !request) { + return ( +
+
{error}
+ +
+ ) + } + + if (!request) { + return
Loading…
+ } + + return ( + <> +
+
+
+
+ Request id +
+ {request.id} +
+ {request.status} +
+

+ Migrating from @{request.oldHandle} to{' '} + @{request.newUserHandle} +

+
+ + {request.status === 'pending' && ( +
+

+ Waiting for an Audius team member to review. You can leave this + page open — it polls every few seconds. The team will reach out + via your usual support channel if they need to verify your + identity before approving. +

+
+ )} + + {request.status === 'rejected' && ( +
+

+ Rejected.{' '} + {request.rejectionReason ?? 'No reason given.'} +

+ +
+ )} + + {request.status === 'failed' && ( +
+

+ Migration failed.{' '} + {request.failureReason ?? 'See per-track results below.'} +

+
+ )} + +
+

Tracks ({request.tracks.length})

+
    + {request.tracks.map((t) => { + const result = request.results?.find( + (r) => r.oldTrackId === t.trackId + ) + return ( +
  • + {t.artworkUrl ? ( + + ) : ( +
    + )} +
    +
    {t.title}
    +
    + {t.genre ?? 'Unknown genre'} + {result?.newTrackId && ( + <> + {' · '} + new id: {result.newTrackId} + + )} + {result?.error && ( + <> + {' · '} + {result.error} + + )} +
    +
    + {result && ( + + {result.status} + + )} +
  • + ) + })} +
+
+ + ) +} diff --git a/packages/migrate-tool/src/sdk.ts b/packages/migrate-tool/src/sdk.ts new file mode 100644 index 00000000000..af5c841ff51 --- /dev/null +++ b/packages/migrate-tool/src/sdk.ts @@ -0,0 +1,22 @@ +import type { AudiusSdk } from '@audius/sdk' +import { sdk } from '@audius/sdk' + +import { config } from './config' + +const APP_NAME = 'AudiusTrackMigration' + +let sdkInstance: AudiusSdk | null = null + +export function getSDK(): AudiusSdk { + if (sdkInstance) return sdkInstance + const redirectUri = window.location.origin + window.location.pathname + sdkInstance = config.apiKey + ? sdk({ + appName: APP_NAME, + apiKey: config.apiKey, + redirectUri, + environment: config.environment + }) + : sdk({ appName: APP_NAME, redirectUri, environment: config.environment }) + return sdkInstance +} diff --git a/packages/migrate-tool/src/styles.css b/packages/migrate-tool/src/styles.css new file mode 100644 index 00000000000..431826dc0f6 --- /dev/null +++ b/packages/migrate-tool/src/styles.css @@ -0,0 +1,190 @@ +:root { + color-scheme: light; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + --color-bg: #f7f7fa; + --color-card: #ffffff; + --color-border: #e1e1e8; + --color-text: #1d1d28; + --color-muted: #6b6b78; + --color-primary: #7e1bcc; + --color-primary-hover: #6a18ad; + --color-danger: #c43c3c; + --color-success: #2e8b57; +} + +* { box-sizing: border-box; } + +body { + margin: 0; + background: var(--color-bg); + color: var(--color-text); +} + +.app { + max-width: 820px; + margin: 0 auto; + padding: 32px 20px 64px; +} + +.header h1 { + margin: 0 0 8px; + font-size: 28px; +} + +.header h1 a { + color: inherit; + text-decoration: none; +} + +.tagline { + margin: 0 0 32px; + color: var(--color-muted); +} + +.card { + background: var(--color-card); + border: 1px solid var(--color-border); + border-radius: 12px; + padding: 24px; + margin-bottom: 20px; +} + +.card h2 { margin-top: 0; } + +label { + display: block; + font-weight: 600; + margin-bottom: 8px; +} + +input[type='text'], +input[type='password'] { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--color-border); + border-radius: 8px; + font-size: 15px; + background: white; +} + +button { + background: var(--color-primary); + color: white; + border: none; + padding: 10px 18px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; + cursor: pointer; +} + +button:hover:not(:disabled) { background: var(--color-primary-hover); } +button:disabled { opacity: 0.5; cursor: not-allowed; } + +button.secondary { + background: transparent; + color: var(--color-primary); + border: 1px solid var(--color-primary); +} + +button.danger { background: var(--color-danger); } +button.danger:hover:not(:disabled) { background: #a82c2c; } + +.error { + background: #fbe5e5; + color: var(--color-danger); + padding: 12px 14px; + border-radius: 8px; + margin-bottom: 16px; +} + +.note { + background: #fff8e1; + border-left: 4px solid #f6c343; + padding: 12px 14px; + border-radius: 4px; + font-size: 14px; + margin-bottom: 16px; +} + +.track-list { + list-style: none; + padding: 0; + margin: 16px 0 0; +} + +.track-list li { + display: flex; + gap: 12px; + align-items: center; + padding: 10px 0; + border-bottom: 1px solid var(--color-border); +} + +.track-list li:last-child { border-bottom: none; } + +.track-art { + width: 48px; + height: 48px; + border-radius: 6px; + background: #ddd; + object-fit: cover; + flex-shrink: 0; +} + +.track-meta { + flex: 1; + min-width: 0; +} + +.track-title { + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.track-sub { + color: var(--color-muted); + font-size: 13px; +} + +.badge { + display: inline-block; + padding: 2px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 600; + background: #eaeaea; + color: var(--color-muted); +} + +.badge.pending { background: #fff3cd; color: #856404; } +.badge.approved { background: #d4edda; color: #155724; } +.badge.running { background: #d1ecf1; color: #0c5460; } +.badge.completed { background: #d4edda; color: #155724; } +.badge.failed { background: #f8d7da; color: #721c24; } +.badge.rejected { background: #f8d7da; color: #721c24; } +.badge.success { background: #d4edda; color: #155724; } + +.row { + display: flex; + gap: 12px; + align-items: center; + justify-content: space-between; +} + +.muted { color: var(--color-muted); } + +.footer { + margin-top: 48px; + padding-top: 16px; + border-top: 1px solid var(--color-border); + text-align: center; + font-size: 13px; +} + +.footer a { + color: var(--color-muted); + text-decoration: none; +} diff --git a/packages/migrate-tool/src/types.ts b/packages/migrate-tool/src/types.ts new file mode 100644 index 00000000000..a0eae2a13ac --- /dev/null +++ b/packages/migrate-tool/src/types.ts @@ -0,0 +1,39 @@ +export type RequestStatus = + | 'pending' + | 'approved' + | 'running' + | 'completed' + | 'failed' + | 'rejected' + +export type TrackPreview = { + trackId: string + title: string + genre?: string | null + durationSec?: number | null + artworkUrl?: string | null + isDownloadable: boolean + hasOriginal: boolean +} + +export type TrackResult = { + oldTrackId: string + newTrackId?: string + status: 'pending' | 'success' | 'failed' + error?: string +} + +export type MigrationRequest = { + id: string + newUserId: string + newUserHandle: string + oldHandle: string + status: RequestStatus + tracks: TrackPreview[] + results?: TrackResult[] + createdAt: string + approvedAt?: string | null + completedAt?: string | null + rejectionReason?: string | null + failureReason?: string | null +} diff --git a/packages/migrate-tool/src/vite-env.d.ts b/packages/migrate-tool/src/vite-env.d.ts new file mode 100644 index 00000000000..88a0543401d --- /dev/null +++ b/packages/migrate-tool/src/vite-env.d.ts @@ -0,0 +1,10 @@ +/// + +interface ImportMetaEnv { + readonly VITE_AUDIUS_API_KEY?: string + readonly VITE_AUDIUS_ENVIRONMENT?: 'development' | 'production' +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/packages/migrate-tool/supabase/migrations/0001_init.sql b/packages/migrate-tool/supabase/migrations/0001_init.sql new file mode 100644 index 00000000000..4fa6f4142c5 --- /dev/null +++ b/packages/migrate-tool/supabase/migrations/0001_init.sql @@ -0,0 +1,31 @@ +-- Migration requests for the Audius track migration tool. +-- One row per submitted migration; status drives the approval workflow. + +create extension if not exists "pgcrypto"; + +create table if not exists migration_requests ( + id uuid primary key default gen_random_uuid(), + new_user_id text not null, + new_user_handle text not null, + old_handle text not null, + status text not null default 'pending' + check (status in ('pending','approved','running','completed','failed','rejected')), + tracks jsonb not null, + results jsonb, + rejection_reason text, + failure_reason text, + created_at timestamptz not null default now(), + approved_at timestamptz, + completed_at timestamptz +); + +create index if not exists migration_requests_status_idx + on migration_requests (status, created_at desc); + +create index if not exists migration_requests_new_user_idx + on migration_requests (new_user_id); + +-- RLS stays off: every API call hits the service role key from a Vercel +-- function. Browsers never touch this table directly. Re-enable RLS and +-- write policies if that ever changes. +alter table migration_requests disable row level security; diff --git a/packages/migrate-tool/tsconfig.api.json b/packages/migrate-tool/tsconfig.api.json new file mode 100644 index 00000000000..10018e14887 --- /dev/null +++ b/packages/migrate-tool/tsconfig.api.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["node"] + }, + "include": ["api"] +} diff --git a/packages/migrate-tool/tsconfig.app.json b/packages/migrate-tool/tsconfig.app.json new file mode 100644 index 00000000000..e2397ee341e --- /dev/null +++ b/packages/migrate-tool/tsconfig.app.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/packages/migrate-tool/tsconfig.json b/packages/migrate-tool/tsconfig.json new file mode 100644 index 00000000000..0bbb4ce2393 --- /dev/null +++ b/packages/migrate-tool/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.api.json" } + ] +} diff --git a/packages/migrate-tool/vercel.json b/packages/migrate-tool/vercel.json new file mode 100644 index 00000000000..e61b33bd813 --- /dev/null +++ b/packages/migrate-tool/vercel.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "buildCommand": "npm run build", + "outputDirectory": "dist", + "rewrites": [ + { "source": "/((?!api/).*)", "destination": "/index.html" } + ], + "functions": { + "api/admin/approve.ts": { + "maxDuration": 300 + } + } +} diff --git a/packages/migrate-tool/vite.config.ts b/packages/migrate-tool/vite.config.ts new file mode 100644 index 00000000000..09faa669d66 --- /dev/null +++ b/packages/migrate-tool/vite.config.ts @@ -0,0 +1,25 @@ +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' +import { nodePolyfills } from 'vite-plugin-node-polyfills' + +export default defineConfig({ + plugins: [ + react(), + // The SDK references Buffer / process at runtime — keep these polyfilled + // so it works in the browser without a separate global shim. + nodePolyfills({ + include: ['buffer', 'process'], + globals: { Buffer: true, process: true } + }) + ], + server: { + port: 5180, + open: true + }, + build: { + outDir: 'dist', + // The SDK pulls in heavy deps (viem, solana). Pin the chunk limit a bit + // higher so the build doesn't spam warnings — it's a leaf app, not a lib. + chunkSizeWarningLimit: 1500 + } +})